これ何て呼びますか

ソケットプログラミング について
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;
}

質問者からの補足コメント

  • サーバプログラムをコンパイルして実行したら画像のようになります。その後HTMLファイルを開いても何も変わりません

    「ソケットプログラミング について c言語」の補足画像1
      補足日時:2020/12/31 21:48

A 回答 (3件)

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ファイルを開いても何も変わりません」がなにをやったのかは不明ですけども。
    • good
    • 0

>-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バイトです。
    • good
    • 0

お約束ですが…どう「うまくいきません」なんでしょう?



Linux系でも同じかは不明ですが…
>if (read(sockfd, buf, 1024) <= 0 ) {
1回のread()で、すべて読み込める。という保証は無い…かも知れません。
# HTTPリクエストヘッダが1回で受信されない可能性もある。と想定するべきかと。
#まぁ、リクエストヘッダのサイズなんてたかが知れているので、たいていは1回で読める…とは思いますが。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!