Recv()跳过字节

Recv()跳过字节,c,sockets,C,Sockets,我在一个基本的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中调试时,我可以

我在一个基本的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);
    }
}

在本例中,检查recv的返回值有助于回应Michael Burrs的评论。我得出的结论是,最后一次recv调用并没有读取所有字节,而是只读取剩余的字节。在本例中为1或2。然后将字节放在开头,而不会覆盖旧值。我认为这种组合让我很困惑。

您需要始终检查recv的返回值。它不仅告诉您错误,还告诉您调用实际返回了多少字节。