【发布时间】:2021-02-09 20:35:25
【问题描述】:
我有一个用 C 编写的简单 XMLHttpRequest 处理程序。它读取和处理来自在浏览器中运行的 JavaScript XMLHttpRequest send() 的请求。
父进程接受传入的连接,并为每个传入的连接派生一个子进程来读取和处理数据。
它适用于大多数请求,但如果请求长度超过 2K 字节,则在某些情况下会失败(显然与客户端和服务器之间的网络基础设施有关)。我假设请求在浏览器和我的套接字服务器之间的某处被分解为多个数据包。
我无法更改请求格式,但我可以看到正在发送的请求并验证内容。数据是一个“GET”,带有一个包含“type”字段的编码 URI。如果类型是“文件”,则请求可能长达3K,否则最多几百字节。 “文件”请求很少 - 用户正在提供要写入服务器上文件的配置数据。所有其他请求都可以正常工作,任何小于 2K 的“文件”请求都可以正常工作。
在这种情况下,确保我拥有所有数据的首选技术是什么?
这是接受连接并分叉子代的父代部分(非阻塞版本):
for (hit = 1;; hit++) {
length = sizeof(cli_addr);
if ((socketfd = accept4(listensd, (struct sockaddr *) &cli_addr, &length, SOCK_NONBLOCK)) < 0){
//if ((socketfd = accept(listensd, (struct sockaddr *) &cli_addr, &length)) < 0){
exit(3);
}
if ((pid = fork()) < 0) {
exit(3);
} else {
if (pid == 0) { /* child */
//(void) close(listensd);
childProcess(socketfd, hit); /* never returns. Close listensd when done*/
} else { /* parent */
(void) close(socketfd);
}
}
}
这是执行初始recv() 的子进程部分。在长“文件”请求的情况下,孩子的第一个套接字 recv() 会获得大约 1700 字节的有效负载,然后是浏览器提供的连接数据。
ret = recv(socketfd, recv_data, BUFSIZE, 0); // read request
if (ret == 0 || ret == -1) { // read failure stop now
sprintf(sbuff, "failed to read request: %d", ret);
logger(&shm, FATAL, sbuff, socketfd);
}
recv_data[ret] = 0;
len = ret;
如果类型是“文件”,则可能有更多数据。子进程永远不会得到其余的数据。如果套接字阻塞,第二次读取尝试就会挂起。如果套接字是非阻塞的(如下面的 sn-p 所示),所有后续读取都返回 -1 并返回错误“资源暂时不可用”,直到超时:
// It's a file. Could be broken into multiple blocks. Try second read
sleep(1);
ret = recv(socketfd, &recv_data[len], BUFSIZE, 0); // read request
while (ret != 0){
if(ret > 0){
recv_data[len+ret] = 0;
len += ret;
} else {
sleep(1);
}
ret = recv(socketfd, &recv_data[len], BUFSIZE, 0); // read request
}
我预计当客户端关闭连接时 read() 会返回 0,但事实并非如此。
【问题讨论】:
-
当数据不立即可用时,非阻塞套接字会引发错误。它的基本意思是“稍后再试”。您可以使用
select来确定套接字是否已准备好进行读/写,或者不使用非阻塞套接字。如果您从未获得更多数据,则服务器可能未正确发送数据。提供可重现的示例以进一步调试。 -
"如果您从未获得更多数据,那么服务器可能没有正确发送数据" - 或者,更有可能的是,您没有读取/处理数据正确,因此在达到请求结束时不知道何时停止读取。显示的代码绝对不是从 XMLHttpRequest 客户端读取请求的正确方法。
-
“所以当请求结束时不知道何时停止阅读。” - 没错,但我也不知道什么时候需要阅读更多。 read() 的返回值似乎没有帮助。是否有我缺少的套接字选项或内容标题技巧?
标签: sockets xmlhttprequest packet recv