【问题标题】:Recv() skips bytesRecv() 跳过字节
【发布时间】:2017-04-16 00:54:00
【问题描述】:

我在基本 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() 的返回值。它不仅会告诉您错误,还会告诉您调用实际返回了多少字节。

标签: c sockets


【解决方案1】:

在这种情况下检查 recv 的返回值会有所帮助(作为对 Michael Burrs 评论的回应)。我得出的结论是,最后一次 recv 调用不会读取所有字节,而只会读取剩余的字节。在这种情况下是 1 或 2。然后将字节放在开头,而旧值不会被覆盖。我觉得这个组合让我很困惑。

【讨论】:

    猜你喜欢
    • 2021-01-21
    • 2011-12-13
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多