ソケットプログラミング について
c言語で下の条件ようなサーバプログラムを作りたいのですがうまくいきません。どうすれば良いのでしょうか?お願いします。
• HTTPリクエストを処理する簡単なWebサーバプログラム
• Webサーバの仕様
• HTTP request messageを受信・解析する
• 要求されたファイルをサーバのファイルシステムから取得する
• HTTP response messageを作成・送信する
• 要求されたファイルとその前にHTMLヘッダなどをつける
#include <sys/socket.h>//socket(), bind(), accept(), listen()
#include <arpa/inet.h>// struct sockaddr_in, struct sockaddr, inet_ntoa()
#include <netinet/in.h>#include <unistd.h>//close()
#include <netdb.h>#include <sys/types.h>#include <sys/fcntl.h>#include <stdio.h>//printf(), fprintf(), perror()
#include <stdlib.h>//atoi(), exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <string.h>//memset()
#include <errno.h>#define BUF_LEN 1024
#define NAME_LEN 256
void httpd(int sockfd);
int send_msg(int fd, char *msg);
void main()
{
int sockfd, new_sockfd;
int writer_len;
int http_port = 12345; // サーバのポート番号のデフォルト値
struct sockaddr_in reader_addr, writer_addr;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
fprintf(stderr, "error: socket()\n");
fprintf(stderr, "error code is %d\n",errno);
close(sockfd);
exit(1);
}
fprintf(stderr, "socket () passed. socket descriptor=%d.\n",sockfd);
memset(&reader_addr, 0, sizeof(reader_addr));
reader_addr.sin_family = AF_INET;
reader_addr.sin_addr.s_addr = htonl(INADDR_ANY);
reader_addr.sin_port = htons(http_port);
if (bind(sockfd, (struct sockaddr *)&reader_addr, sizeof(reader_addr)) <0) {
fprintf(stderr, "error: bind()\n");
fprintf(stderr, "error code is %d\n",errno);
close(sockfd);
exit(1);
}
fprintf(stderr, "bind () passed\n");
if (listen(sockfd, 5) <0) {
fprintf(stderr, "error: listen()\n");
fprintf(stderr, "error code is %d\n",errno);
close(sockfd);
exit(1);
}
fprintf(stderr, "listen () passed\n");
while(1) {
if ((new_sockfd = accept(sockfd,(struct sockaddr *)&writer_addr, &writer_len)) <0) {
fprintf(stderr, "error: accepting a socket.\n");
fprintf(stderr, "error code is %d\n",errno);
break;
} else {
httpd(new_sockfd);
close(new_sockfd);
}
}
close(sockfd);
}
void httpd(int sockfd)
{
int len;
int read_fd; // 送信するファイルのファイル記述子
char buf[BUF_LEN]; // 送信するファイルを格納するバッファ
char send_buf[BUF_LEN]; // 送信するメッセージを格納するバッファ
char meth_name[16]; // 抽出したメソッド名を格納する変数
char uri_addr[256]; // 抽出したURI格納する変数
char http_ver[64]; // 抽出したhttp version格納する変数
char *uri_file;
if (read(sockfd, buf, 1024) <= 0 ) {
fprintf(stderr, "error: reading a request.\n");
} else {
sscanf(buf, "%s %s %s", meth_name, uri_addr, http_ver);
fprintf(stderr, "method = %s, uri = %s, http_ver = %s\n",meth_name, uri_addr, http_ver);
if (strcmp(meth_name, "GET") != 0) {
send_msg(sockfd, "501 Not Implemented");
} else {
uri_file = uri_addr+1;
//fprintf(stderr, "uri = %s\n",uri_file);
if ((read_fd = open(uri_file, O_RDONLY, 0666)) == -1) {
send_msg(sockfd, "404 Not Found");
} else {
//send_msg(sockfd, "HTTP/1.1 200 OK\r\n");
sprintf(send_buf,"%s 200 OK\r\n",http_ver);
//fprintf(stderr,"%s",send_buf);
send_msg(sockfd, send_buf);
send_msg(sockfd, "text/html\r\n");
send_msg(sockfd, "\r\n");
while((len = read(read_fd, buf, 1024)) >0) {
if (write(sockfd, buf, len) != len) {
fprintf(stderr, "error: writing a response.\n");
break;
}
}
close(read_fd);
}
}
}
}
int send_msg(int fd, char *msg) {
int len;
len = strlen(msg);
if ( write(fd, msg, len) != len ){
fprintf(stderr, "error: writing.");
}
return len;
}
No.2ベストアンサー
- 回答日時:
Ubuntu 20.04でちょっとテスト。
sudo付で起動したときは…
user@vmlts:~$ sudo ./a.out
[sudo] user のパスワード:
socket () passed. socket descriptor=3.
bind () passed
listen () passed
method = GET, uri = /a.html, http_ver = HTTP/1.1
となりました。
ちなみに、別に開いたターミナルから
wget http://127.0.0.1:12345/a.html
を実行しました。
ファイルは以下のような感じ。
user@vmlts:~/Temp$ ls -l ../
drwxr-xr-x 2 user user 4096 5月 10 2020 Desktop
drwxr-xr-x 2 user user 4096 5月 10 2020 Documents
drwxr-xr-x 2 user user 4096 5月 10 2020 Downloads
drwxr-xr-x 2 user user 4096 5月 10 2020 Music
drwxr-xr-x 2 user user 4096 5月 10 2020 Pictures
drwxr-xr-x 2 user user 4096 5月 10 2020 Public
drwxrwxr-x 3 user user 4096 1月 2 17:43 Temp
drwxr-xr-x 2 user user 4096 5月 10 2020 Templates
drwxr-xr-x 2 user user 4096 5月 10 2020 Videos
-rw-rw-r-- 1 user user 6 1月 2 17:42 a.heml
-rwxrwxr-x 1 user user 17640 1月 2 17:40 a.out
-rw-rw-r-- 1 user user 3944 1月 2 17:40 qa12109329.c
ちなみに、wgetで取得した内容は
"404 Not Found"でした。
sudo付で起動して、カレントディレクトリなどはどこになっていたんでしょうかねぇ…
# /rootかな? /procでプロセスの状態は未確認です。
sudoなしで起動した場合は…
user@vmlts:~$ ./a.out
socket () passed. socket descriptor=3.
bind () passed
listen () passed
error: accepting a socket.
error code is 22
でした。
#define EINVAL 22 /* Invalid argument */
ですな。
「その後HTMLファイルを開いても何も変わりません」がなにをやったのかは不明ですけども。
No.3
- 回答日時:
>-rw-rw-r-- 1 user user 6 1月 2 17:42 a.heml
>wget http://127.0.0.1:12345/a.html
ファイル名間違っていただけだった…
正しいファイル名にリネームして、wgetで正しく転送されました。
ちなみにWebブラウザでやっていたわけではないので中身は"Test"と改行だけなので6バイトです。
No.1
- 回答日時:
お約束ですが…どう「うまくいきません」なんでしょう?
Linux系でも同じかは不明ですが…
>if (read(sockfd, buf, 1024) <= 0 ) {
1回のread()で、すべて読み込める。という保証は無い…かも知れません。
# HTTPリクエストヘッダが1回で受信されない可能性もある。と想定するべきかと。
#まぁ、リクエストヘッダのサイズなんてたかが知れているので、たいていは1回で読める…とは思いますが。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# プログラミングの問題です。至急教えてください。 /***から***/の部分をプログラミングにしてほし 1 2022/10/13 11:48
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- Excel(エクセル) 2つのVBAを一緒にしたら機能しなくなりました(エクセル) 7 2022/06/02 12:41
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
charでの計算?
-
charからLPTSTRへの変換方法
-
文字列から空白を取り除きたい...
-
double型の値をchar配列に変換...
-
c言語でユーザ関数を利用して入...
-
テキストデータをそのままバイ...
-
C言語について。
-
CStringをwchar_tに変換したい
-
enumの記述について。
-
アルファベットの並べ替え
-
'const char *' 型は 'char *' ...
-
3桁区切(コンマ)記号をつけ...
-
C言語のポインターで詰まっている
-
switch文で文字を比較すること...
-
pingの結果を取得する方法
-
配列をnビットシフトする
-
for文 アスタリスクで形を作る
-
ncursesで...
-
C言語の入力した文字を反転させ...
-
Visual Studio strcpyについて
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
C言語のfor文です。 繰り返しの...
-
テキストデータをそのままバイ...
-
charでの計算?
-
文字列から空白を取り除きたい...
-
charからLPTSTRへの変換方法
-
atoi( ) の反対をやりたい
-
2曲同時再生するにはどうした...
-
C言語の入力した文字を反転させ...
-
配列をnビットシフトする
-
3桁区切(コンマ)記号をつけ...
-
int main()の・・・
-
型変換
-
CStringをwchar_tに変換したい
-
'const char *' 型は 'char *' ...
-
間接操作のレベルとは
-
double型の値をchar配列に変換...
-
絶対パスからのファイル名の切...
-
switch文で文字を比較すること...
-
c++ 文字列を入力して、一文字...
おすすめ情報
サーバプログラムをコンパイルして実行したら画像のようになります。その後HTMLファイルを開いても何も変わりません