【发布时间】:2019-01-25 18:33:35
【问题描述】:
我正在为 Windows 和 Linux 上的 Berkley 套接字编写一个包装器。测试程序出现问题:
char buf[BUFSIZE];
int res = 0;
while((res = NetRecv(sock, buf, BUFSIZE, 0)) > 0) // 'NetRecv' is pointing to 'recv'
{
buf[res-1] = '\0';
printf("%s", buf);
}
响应是对网页内容的 HTTP-Get 请求。套接字正在流式传输。
'NetRecv' 已正确初始化 - 也就是说,没有函数指针的类型不匹配,我已经检查过了。
因此,Windows 版本完美运行,Linux 版本在阅读完所有页面后卡住。也就是说,上一个'NetRecv'调用的前一个接收响应的最后一个块,输出它,并且下一个(最后一个)调用只是阻塞。关闭终端会导致“SIGHUP”信号。 看起来 Linux 版本只是没有意识到,它收到了最后一块数据并等待更多。
它应该是这样吗?那不明白,为什么会有阻塞调用的可能性。 现在,我当然可以进行非阻塞调用并使用“select”,但我真的必须这样做吗?
提前致谢)
编辑: 最小的工作示例(省略所有检查,网络函数是标准函数,也经过测试):
int sock = socket(AF_INET, SOCK_STREAM, 0);
// Here getting good IP address of google.com - no problem here
char serv_ip[IPADDR_BUFSIZE];
GetHostAddrByName(AF_INET, "www.google.com", serv_ip, IPADDR_BUFSIZE);
// ip ver site out buf out buf size
// The routine above is made with 'getaddrinfo', to be precise
printf("Current IP of '%s' is '%s'.\n", SERV_URL, serv_ip);
// Copying IP string to address struct
struct sockaddr_in addr;
NetIpFromStr(AF_INET, serv_ip, &addr.sin_addr);
addr.sin_family = AF_INET;
addr.sin_port = NetHtons(80);
connect(sock, (const struct sockaddr*)&addr, sizeof(addr));
const char* msg = "GET / HTTP/1.1\r\n\r\n";
send(sock, msg, strlen(msg), 0);
char buf[BUFSIZE];
int res = 0;
while((res = recv(sock, buf, BUFSIZE-1, 0)) > 0)
{
buf[res] = '\0';
printf("%s", buf);
}
编辑 2:重要提示:当读取所有数据时,Windows 版本也会阻止调用。关闭终端不会使程序崩溃,就像在 Linux 中发生的那样。因此,整个问题是这样的:如何实现读取所有数据?
【问题讨论】:
-
请提供minimal complete and verifiable example 以增加您获得答案的机会。
-
buf[res-1] = '\0';覆盖收到的最后一个字符。使用 'buf[res] = '\0';'并将缓冲区超大一; 'char buf[1+BUFSIZE];',或简称:'NetRecv(sock, buf, BUFSIZE-1, 0)'。
-
HTTP 的哪个版本?如果连接没有被服务器关闭,并且你没有解析 header 来获取 content-length,你将不知道你什么时候收到了所有的数据。
-
int res应该是ssize_t res。 -
Enen 更好 - 在网络代码中完全不要依赖 NUL 终止符:)