【问题标题】:Why is my http server printing out the same bytes? (C)为什么我的 http 服务器打印出相同的字节? (C)
【发布时间】:2018-03-31 17:55:25
【问题描述】:

我刚刚开始了一项任务,我必须创建一个简单的服务器来处理 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++;
      }
    }

然而,相反,我只是让我的控制台交替发送&lt;\r&gt; 和一些奇怪的正方形,里面写着看起来像 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;
}

【问题讨论】:

  • 调试器显示缓冲区中的内容是什么?
  • @pm100 抱歉,我不确定您的意思?我基本上只是将 emacs 用作文本编辑器并在终端中编译
  • 你应该学习如何在调试器下运行你的程序。在将成为 gdb 的 linux 上,您可以暂停程序检查数据等 google 'getting started with gdb'

标签: c http server


【解决方案1】:

您为 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 &lt;errno.h&gt; 以使其存在。)

在我的机器上运行你的代码会给我57,这是Socket not connected,所以你的逻辑中有另一个错误。

在 google 上快速搜索即可发现问题:

你正在发送到监听套接字,当你应该发送到 接受/连接的。

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>

【讨论】:

  • 我刚刚更改了我的代码,现在当我尝试时,我退出了 while 循环而不打印任何内容,并且我的下一次检查失败(字节!= 0)
  • 哇,看起来我已经准备好客户端变量然后忘记使用它了。我非常感谢您花时间帮助我解决这个问题。现在一切正常。
  • @toastedDeli 不客气 :) 很高兴能帮上忙。
猜你喜欢
  • 2014-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-06
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
  • 2019-03-01
相关资源
最近更新 更多