为什么我的http服务器打印出相同的字节? (C)

时间:2017-10-19 16:04:49

标签: c http server

我刚刚开始一项任务,我必须创建一个处理http请求的简单服务器。

为了让我开始,我决定制作一个等待连接的基本服务器,然后连续打印出从read()接收的任何内容。

使用此代码进行打印,我希望看到一个纯文本http请求,其中\ r和\ n分别由<\r><\n>替换(当我在网络中访问http://ip:port时浏览器):

    char buffer[buffer_size];
    size_t bytes;

    while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {
      buffer[bytes] = '\0';
      int i = 0;
      while(buffer[i] != '\0') {
        if (buffer[i] == '\n') {
          printf("%s","<\\n>\n");
        } else if (buffer[i] == '\r') {
          printf("%s","<\\r>");
        } else {
          printf("%c",buffer[i]);
        }
        i++;
      }
    }

然而,相反,我只是让我的控制台发送垃圾邮件,交替使用<\r>和一些奇怪的正方形,内部看起来像001B(这里是我的终端http://gyazo.com/13288989dc0c1f4782052a1914eb7f84图片的链接)。这是我的代码的问题吗? Mozilla是否会故意发送垃圾邮件?

编辑:我的所有代码:

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

#define buffer_size 1024


int main(int argc, char **argv) {
  int port;
  int client;
  struct sockaddr_in6 my_add;
  struct sockaddr_in6 their_add;
  socklen_t their_add_size = sizeof(their_add);

  if (argc != 2) {
    printf("%s\n","Usage: ./server <port>");
    return -1;
  }

  port = atoi(argv[1]);

  my_add.sin6_family = AF_INET6;
  my_add.sin6_addr = in6addr_any;
  my_add.sin6_port = htons(port);

  int s = socket(PF_INET6, SOCK_STREAM, 0);

  if (s < 0) {
    printf("%s","error on socket()");
    return -1;
  }

  if (bind (s, (struct sockaddr *) &my_add, sizeof(my_add)) != 0) {
    printf("%s","error on bind()");
    return -1;
  }

  if (listen (s, 5) != 0) {
    printf("%s","error on listen()");
    return -1;
  }

  client = accept(s, (struct sockaddr *) &their_add, &their_add_size);
  printf("%s","connected");

  char buffer[buffer_size];
  size_t bytes;

  while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {
    buffer[bytes] = '\0';
    int i = 0;
    while(buffer[i] != '\0') {
      if (buffer[i] == '\n') {
    printf("%s","<\\n>\n");
      } else if (buffer[i] == '\r') {
    printf("%s","<\\r>");
      } else {
    printf("%c",buffer[i]);
      }
      i++;
    }
  }

  if (bytes != 0) {
    printf("%s","something went wrong. bytes != 0.");
    return -1;
  }

  printf("%s", "connection closed");
  close(s);
  return 0;
}

1 个答案:

答案 0 :(得分:4)

您对bytes变量使用了错误的数据类型:

read()的函数原型是:

ssize_t read(int, void *, size_t)

但您使用的是未签名的size_tssize_t 签名

因此,如果read()返回一个负数,它会被转换为一个巨大的数字,从而导致无限循环。

您也可以简化代码:

char buffer[buffer_size];
ssize_t bytes;

while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {
    // Just loop over the number of bytes we've just read
    for (ssize_t i = 0; i < bytes; ++i) {
        const char ch = buffer[i];

        // Handle `ch`
        if (ch == '\n') {
            printf("<\\n>\n");
        } else if (ch == '\r') {
            printf("<\\r>");
        } else {
            printf("%c", ch);
        }
    }
}

关于更新的OP问题:

if (bytes != 0) {
    printf("%s","something went wrong. bytes != 0.");
    return -1;
}

应该是:

if (0 > bytes) {
    printf("bytes is negative. ERRNO = %d", errno);

    return -1;
}

(包括#include <errno.h>使其存在。)

在我的计算机上运行代码会为57提供Socket not connected,因此您的逻辑会出现另一个错误。

谷歌上的快速搜索揭示了这个问题:

  

当你要发送给你时,你正在发送到监听套接字   接受/连接的。

Source

所以而不是:

while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {

您应该使用:

while ((bytes = read(client, buffer, buffer_size - 1)) > 0) {

因为您想要从已连接的客户端client读取,而不是您的侦听套接字s

这解决了我的机器上的问题:

./a.out 1337
connectedGET / HTTP/1.1<\r><\n>
Host: localhost:1337<\r><\n>
Connection: keep-alive<\r><\n>
Cache-Control: max-age=0<\r><\n>
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36<\r><\n>
Upgrade-Insecure-Requests: 1<\r><\n>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8<\r><\n>
Accept-Encoding: gzip, deflate, br<\r><\n>
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4<\r><\n>
Cookie: TripmanagerHighlightedParameter_index=flow_l_h<\r><\n>
<\r><\n>