【问题标题】:what could limit bytes read in from read()什么可以限制从 read() 读取的字节
【发布时间】:2012-12-11 11:45:10
【问题描述】:

我正在从这样初始化的套接字读取字节:

fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

但是当我从这个套接字读取时

char buf[ETH_FRAME_LEN]
len = read(fd, buf, sizeof(buf));

len 显示只读取了 1500 个字节。我检查了wireshark,返回的数据包是5854。IP下的总长度字段为5840(所以+ 14字节的以太网头= 5854)。我尝试使用更大的缓冲区(6000),但仍然只有 1500 字节被从线路中读取。

我尝试从服务器请求一个较小的文件(1504 字节),但我得到了相同的结果。由于它是一个原始套接字,因此读入的数据包括以太网标头,因此它不会将最后 4 个字节读入缓冲区。

这可能是什么原因?我不知道socket() 有任何可能导致这种情况的论点。

【问题讨论】:

    标签: sockets


    【解决方案1】:

    如果您再次尝试拨打read 会发生什么情况?下一个消息块是否很快返回?

    来自阅读man page(我的重点)

    read() 尝试读取 最多 个 count 字节

    如果你想读取一定数量的字节,你应该准备好循环调用read,直到你收到你的目标总数。

    【讨论】:

    • hhmm,我改变了它,所以我正在读取两个不同的缓冲区。服务器向我发送了两条大消息。第一次读取读取第一条消息的 1500 字节,第二次读取读取第二条消息的 1500 字节。所以我想这意味着未读取的字节被丢弃。我希望这来自 SOCK_DGRAM/UDP 套接字,但这对于 RAW 套接字是否正常?
    • 我怀疑数据已被丢弃。如果您再试一次,您可能会发现有更多数据可供读取。
    • 嗯,我所做的读取是:len = read(fd, buf, sizeof(buf)); len2 = 读取(fd,buf2,sizeof(buf2));也就是说,来自同一个 fd 的两次连续读取。这就是你说的再试一次吗?
    • 是的。或者您可以声明一个大型缓冲区和循环,更改每次调用时写入的缓冲区中的点,直到您读取目标数据量
    • 如果您没有注意到,Zaffy 提供了我在下面讨论的那种循环的示例。
    【解决方案2】:

    发生的情况是,每次调用 read() 时,您将获得一个以太网 MTU 的有效负载。

    【讨论】:

    • 但由于它是一个 RAW 套接字,我不应该得到整个 1514 字节(即以太网 MTU 为 1500 + 以太网标头为 14)吗?
    【解决方案3】:

    read() 返回:

    成功时,返回读取的字节数(零表示结束 文件),并且文件位置由这个数字提前。 这不是一个 如果此数字小于请求的字节数,则会出错; 例如,这可能会发生,因为实际上可用的字节更少 现在(可能是因为我们接近文件结尾,或者因为我们 正在从管道或终端读取),或者因为 read() 是 被一个信号打断。出错时,返回 -1,并设置 errno 适当地。在这种情况下,未指定文件是否 位置(如果有)发生变化。

    您可以尝试将recv()MSG_WAITALL 一起使用,而不是纯read()

    这个标志要求操作阻塞直到满 要求得到满足。但是,调用可能仍然返回较少 如果捕获到信号、发生错误或断开连接,或者要接收的下一个数据是不同的 类型比返回的类型。

    len = recv(fd, buf, sizeof(buf), MSG_WAITALL);
    

    另一种方法是在循环中读取或接收,例如:

    ssize_t Recv(int fd, void* buf, ssize_t n)
    {
        ssize_t read = 0;
        ssize_t r;
        while(read != n)
        {
            r = recv(fd, ((char*)buf)+read, n-read, 0);
            if(r == -1)
                return (read) ? read : -1;
            if(r == 0)
                return 0;
    
            read += r;
        }
    
        return read;
    }
    

    【讨论】:

    • 嗨,谢谢。当我从同一个套接字进行多次读取时,第一个 read() 读取第一条消息的前 1500 个字节;第二个 read() 从第二个消息中读取前 1500 个字节,而不是第一个消息。
    • @AG 是的,有可能,限制也可以在套接字选项 rcvbuf 中,指定可以等待读取/接收的最大字节长度。您是否尝试过 msg_waitall 和/或循环读取?
    • 嗨,我检查了 rcvbuf,它是 112640 字节,所以这不是问题。当进行多次读取时(例如在一个循环中),recv 调用从下一个以太网帧读取前 1500 个字节,而不是从原始帧读取未读字节。
    猜你喜欢
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    相关资源
    最近更新 更多