我在基本的TCP连接上使用recv。这是我正在阅读的[]字节:[0 4 9 0]
以下是recv调用,最后是上下文中的代码
recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL);
len = ntohs(len);
recv(fd_serv, &tool_id, sizeof (tool_id), MSG_NOSIGNAL);
recv(fd_serv, rdbuf, len, MSG_NOSIGNAL);
在gdb中调试时我可以看到
len = 4
tool_id = 9
rdbuf = [ 0 4 9 0 ] / [ 0 4 \t 0 ]
怎么可能?看起来recv取len的前两个字节和tool_id的下一个字节(如长度/大小),同时取rdbuf的所有字节。我希望它是一致的。我认为这可能是部分字节读取的一个功能,但显然我错了。
如果我删除
recv(fd_serv, &tool_id, sizeof (tool_id), MSG_NOSIGNAL);
从代码中检查gdb中的rdbuf,执行
后的前2个字节更改recv(fd_serv, rdbuf, len, MSG_NOSIGNAL);
它变成了
[ 9 0 9 0 ] / [ \t 0 \t 0 ]
当我再次取消注释时,rdbuf再次正常。起初我以为没有读过的剩余字节被复制了。我将rdbuf [3]设置为5并认为它可能会替换为0,但事实并非如此。到目前为止,我对这里发生的事情以及为何在这里不一致感到无能为力。
我正在使用Arch Linux x86_64 gdb 7.12.1,gcc 6.3.1和它来构建:
gcc -g -DDEBUG *.c -o client.dbg -lcrypto
上下文
while(TRUE) {
if (fd_serv != -1 && FD_ISSET(fd_serv, &fdsetrd)) {
int n;
uint16_t len;
uint8_t tool_id;
char rdbuf[1024];
errno = 0;
n = recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL | MSG_PEEK);
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
continue;
else
n = 0;
}
if (n == 0) {
close_connection();
continue;
}
if (len == 0) {
recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL);
continue;
}
len = ntohs(len);
if (len > sizeof (rdbuf)) {
close(fd_serv);
fd_serv = -1;
}
errno = 0;
n = recv(fd_serv, rdbuf, len, MSG_NOSIGNAL | MSG_PEEK);
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
continue;
else
n = 0;
}
if (n == 0) {
close_connection();
continue;
}
recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL);
len = ntohs(len);
recv(fd_serv, &tool_id, sizeof (tool_id), MSG_NOSIGNAL);
recv(fd_serv, rdbuf, len, MSG_NOSIGNAL);
printf("%d\n", tool_id);
}
}
答案 0 :(得分:1)
在这种情况下检查recv的返回值有帮助(作为对Michael Burrs评论的回复)。我得出的结论是,最后一次recv调用不会读取所有字节,而只会读取剩余的字节。在这种情况下,这是1或2。然后将字节放在开头,而不覆盖旧值。我认为这种组合使我感到困惑。