使用 fork 和 dup 的简单 http 通用服务器
Simple http generic server using fork and dup
我正在尝试编写一个非常基本的 HTTP 服务器。我想将服务器和服务分开在两个单独的可执行文件中(类似于 inetd)。
所以我有一个通用服务器,它分叉一个服务并使用 exec 执行它的代码。主循环如下:
while(true) {
int client_sock;
if ((client_sock = accept(server_sock, (struct sockaddr *) NULL, NULL)) < 0) {
return -1;
}
pid_t pid = fork();
if (pid == 0) {
close(server_sock);
close(0);
dup(client_sock);
close(1);
dup(client_sock);
execvp(argv[2], argv+2);
return -1;
} else if (pid < 0) {
assert(false);
}
close(client_sock);
}
该服务读取标准输入,写入标准输出并处理简单的 http 请求。当我使用 nc 连接到我的服务器时,一切似乎都工作正常。 nc 接收并显示预期的 http 回复。
但是,当我使用网络浏览器连接到我的服务器时,浏览器告诉我服务器突然关闭了连接(我相信是 ECONNRESET 错误)。我确信我的服务处理了请求:我用 strace 检查了我的服务的执行情况,所有预期的 "write(1,...)" 都在那里,并且没有任何 close(1)。更令人惊讶的是,有时,网络浏览器会收到回复。
提供的代码有什么问题吗?如果不是,是什么导致了问题?
我想问题不在于您显示的代码,而在于您执行的程序。一个典型的问题是客户端(即您的程序)不读取 HTTP header 而只是写入数据并完成。在这种情况下,浏览器的文件描述符被关闭,而套接字缓冲区中仍有来自服务器的未处理数据。这导致服务器 OS 发送一个 RST 数据包,然后导致浏览器中的 ECONNRESET。如果幸运的话,浏览器在收到 RST 之前就收到并呈现了响应,所以您有时会看到连接重置错误,有时不会。
我正在尝试编写一个非常基本的 HTTP 服务器。我想将服务器和服务分开在两个单独的可执行文件中(类似于 inetd)。
所以我有一个通用服务器,它分叉一个服务并使用 exec 执行它的代码。主循环如下:
while(true) {
int client_sock;
if ((client_sock = accept(server_sock, (struct sockaddr *) NULL, NULL)) < 0) {
return -1;
}
pid_t pid = fork();
if (pid == 0) {
close(server_sock);
close(0);
dup(client_sock);
close(1);
dup(client_sock);
execvp(argv[2], argv+2);
return -1;
} else if (pid < 0) {
assert(false);
}
close(client_sock);
}
该服务读取标准输入,写入标准输出并处理简单的 http 请求。当我使用 nc 连接到我的服务器时,一切似乎都工作正常。 nc 接收并显示预期的 http 回复。
但是,当我使用网络浏览器连接到我的服务器时,浏览器告诉我服务器突然关闭了连接(我相信是 ECONNRESET 错误)。我确信我的服务处理了请求:我用 strace 检查了我的服务的执行情况,所有预期的 "write(1,...)" 都在那里,并且没有任何 close(1)。更令人惊讶的是,有时,网络浏览器会收到回复。
提供的代码有什么问题吗?如果不是,是什么导致了问题?
我想问题不在于您显示的代码,而在于您执行的程序。一个典型的问题是客户端(即您的程序)不读取 HTTP header 而只是写入数据并完成。在这种情况下,浏览器的文件描述符被关闭,而套接字缓冲区中仍有来自服务器的未处理数据。这导致服务器 OS 发送一个 RST 数据包,然后导致浏览器中的 ECONNRESET。如果幸运的话,浏览器在收到 RST 之前就收到并呈现了响应,所以您有时会看到连接重置错误,有时不会。