我刚刚开始一项任务,我必须创建一个处理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;
}
答案 0 :(得分:4)
您对bytes
变量使用了错误的数据类型:
read()
的函数原型是:
ssize_t read(int, void *, size_t)
但您使用的是未签名的size_t
(ssize_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
,因此您的逻辑会出现另一个错误。
谷歌上的快速搜索揭示了这个问题:
当你要发送给你时,你正在发送到监听套接字 接受/连接的。
所以而不是:
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>