1

私は Web サーバーを作成しようとしていますが、私が持っているコードでは「open failed」になっています。ブラウザで開くことになっている html ドキュメント (ht.html)。

私が持っているコードは次のとおりです。

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define SERVER_PORT 12345
#define BUF_SIZE 4096
#define QUEUE_SIZE 10


int main(int argc, char *argv[])
{
  int s, b, l, fd, sa, bytes, on = 1;
  char buf[BUF_SIZE]; //buffer for outgoing file
  struct hostent *h; //info about server
  struct sockaddr_in channel; //holds IP address

  //Build address structure to bind to socket
  memset(&channel, 0, sizeof(channel)); //zero channel
  channel.sin_family = AF_INET;
  channel.sin_addr.s_addr = htonl(INADDR_ANY);
  channel.sin_port = htons(SERVER_PORT);


  //Passive open. Wait for connection
  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* create socket */
  if (s < 0) fatal("socket failed");
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));


  b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
  if (b < 0) fatal("bind failed");

  l = listen(s, QUEUE_SIZE);        /* specify queue size */
  if (l < 0) fatal("listen failed");


  /* Socket is now set up and bound. Wait for connection and process it. */
  while(1) {
    sa = accept(s, 0, 0);       /* block for connection request */
    if (sa < 0) fatal("accept failed");

    read(sa, buf, BUF_SIZE);    /* read file name from socket */

    /* Get and return the file. */

    fd = open(buf, O_RDONLY);   /* open the file to be sent back */
    if (fd < 0) fatal("open failed");

    while(1){
      bytes = read(fd, buf, BUF_SIZE); /* read from file */
      if (bytes <= 0) break;         /* check for end of file */
      write(sa, buf, bytes);              /*write bytes to socket*/
    }

    close(fd); //close file
    close(sa); //close connection

  }
}

fatal(char*string)
{
  printf("%s", string);
  exit(1);
}

私のエラーはどこですか?または何を追加する必要がありますか?

4

4 に答える 4

1

おそらく、ソケットから受信したデータの出力から始めるか、少なくともデバッガーで実行することができます。そうしないと、何が起こっているのかを知らずに、すべてが暗闇で実行されます。以下のコードではprintf、Web ブラウザーから取得したものを印刷するために を追加しました。

また、他の人が指摘したように、何errnoが私たちに伝えようとしているのかを知ることは良いことです. perror+を使用するのは少し面倒/面倒なので、Linux と BSD ではerr(3)warn(3exit )を使用できます。err は errno メッセージを出力して終了しますが、 warn は errno メッセージを出力するだけで終了しません。関数をこれらに置き換えました。fatal

Web ブラウザが送信する可能性が最も高くGET /ht.html HTTP/1.1\r\n、これが開こうとしているものです。ファイルを開くには、そのht.html部分を抽出する必要があります。以下のコードを更新しました。現在、strchr(3)strstr(3)を使用して を抽出してht.htmlいます。

また、HTTP 応答コードを送信し、HTML を送信することを Web ブラウザーに伝える必要があります。これが、HTTP/1.1 200 OKが送信される理由です。すべての HTTP ヘッダーは\r\n(キャリッジ リターン - 改行) で区切る必要があることに注意してください。HTTP プロトコルの詳細については、RFC 2616を参照してください。

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>

#define SERVER_PORT 12345
#define BUF_SIZE 4096
#define QUEUE_SIZE 10

int main(int argc, char *argv[])
{
  int s, b, l, fd, sa, bytes, on = 1;
  char buf[BUF_SIZE]; /* buffer for outgoing file */
  char *p, *endp, *cp;

  struct sockaddr_in channel; /* holds IP address */

  /* Build address structure to bind to socket */
  memset(&channel, 0, sizeof(channel)); /* zero channel */
  channel.sin_family = AF_INET; /* ipv4 */
  channel.sin_addr.s_addr = htonl(INADDR_ANY); /* 0.0.0.0 */
  channel.sin_port = htons(SERVER_PORT);


  /* Passive open. Wait for connection */
  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* create socket */
  if (s < 0) err(1, "socket failed");
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

  b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
  if (b < 0) err(1, "bind failed");

  l = listen(s, QUEUE_SIZE);        /* specify queue size */
  if (l < 0) err(1, "listen failed");


  /* Socket is now set up and bound. Wait for connection and process it. */
  while(1) {
    sa = accept(s, NULL, NULL);       /* block for connection request */
    if(sa < 0) {
      warn("accept failed");
      continue;
    }

    bytes = 0;
    endp = buf + sizeof(buf); /* pointer to end of buf */
    cp = NULL;
    buf[0] = '\0';
    /* read first line from socket */
    /* should be "GET /[file] HTTP/1.1" */
    for(p = buf; (bytes = read(sa, p, endp - p)) > 0; p += bytes) {
      p[bytes] = '\0'; /* read(2) doesn't NUL terminate buf */
      if((cp = strchr(p, '\r')) != NULL) /* break at first carriage return */
        break;
    }
    printf("incoming request %lu bytes:\n%s\n", strlen(buf), buf);
    /* no carrige return or no "GET /" was found */
    if(cp == NULL || strstr(buf, "GET /") != buf) { 
      warnx("incomplete request");
      close(sa);
      continue;
    }
    *cp = '\0'; /* replace '\r' with '\0' */
    p = buf + sizeof("GET /") - 1; /* point to after "GET /" */
    cp = strchr(p, ' '); /* find " HTTP/1.1" */
    if(cp == NULL) {
      warnx("HTTP version was not found");
      close(sa);
      continue;
    }
    *cp = '\0'; /* replace ' ' with '\0' */


    /* Get and return the file. */
    fd = open(p, O_RDONLY);   /* open the file to be sent back */
    if(fd < 0) {
      warn("open failed: %s", p);
      close(fd);
      close(sa);
      continue;
    }

    /* Send HTTP header */
    /* Should probably also send Content-Length: <sizeof file>, */
    /* this can be checked using fstat(2) */
    write(sa, "HTTP/1.1 200 OK\r\n" \
      "Content-Type: text/html;charset=UTF-8\r\n\r\n", 58);
    while(1) {
      bytes = read(fd, buf, sizeof(buf)); /* read from file */
      if (bytes <= 0) break;         /* check for end of file */
      write(sa, buf, bytes);              /*write bytes to socket*/
    }

    close(fd); /* close file */
    close(sa); /* close connection */
  }
  return 0;
}

Web ブラウザーから HTTP サーバーに接続するには、次の場所に移動しますhttp://127.0.0.1:12345/ht.html

于 2013-02-23T18:40:19.727 に答える
0

ブラウザから読み取っているものは HTTP リクエストです。

これをデコードする必要があるため、HTTPの仕様を読んでください。

HTTP リクエストの例はここにあります

于 2013-02-24T13:27:12.163 に答える
0
  1. ERRNO を探してみてください。

    if (fd < 0) perror("open failed");
    
  2. バフを見てみてください。

    if (fd < 0){ 
      printf("%s\n", buf);
      perror("open failed");
    }
    
  3. このように buf を見てみてください:

    if (fd < 0){
      for(i=0;i<strlen(buf);i++) 
         printf("%d", buf[i]);
      perror("open failed");
    }
    

アプリケーションは単純にファイルを開かないため、エラーを理解するにはこれで十分です。

于 2013-02-23T18:48:03.543 に答える
0

デバッグ メッセージを追加するか、デバッガで実行してみてください。

問題は open ステートメントに渡されるバッファに依存していると思います。buf はゼロで初期化されておらず、「読み取り」によって NULL で終了していないようです。

n = read(sa, buf, BUF_SIZE);
buf[n] = '\0';

一般に、read を使用する場合は、0 または -1 が返されるまでループで呼び出す必要があります。バッファーの一部しか満たしていない可能性があります。

于 2013-02-23T18:50:11.343 に答える