首页 文章

在套接字库中调用recv时,我的recv缓冲区应该有多大

提问于
浏览
115

我对C中的套接字库有几个问题 . 这是我在问题中引用的一段代码 .

char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);
  • 如何判断recv_buffer的大小?我是'm using 3000, but it'是任意的 .

  • 如果 recv() 收到的数据包大于我的缓冲区会怎么样?

  • 如果没有再次调用recv,我怎么知道我是否收到了整个消息,并且在没有任何东西被接收时让它永远等待?

  • 有没有办法可以让缓冲区没有固定的空间,这样我可以继续添加它而不用担心空间不足?也许使用 strcat 将最新的 recv() 响应连接到缓冲区?

我知道这里有很多问题,但我非常感谢任何回复 .

6 回答

  • 1

    这些问题的答案取决于您是使用流套接字( SOCK_STREAM )还是数据报套接字( SOCK_DGRAM ) - 在TCP / IP中,前者对应TCP,后者对应UDP .

    你怎么知道将缓冲区传递给 recv() 有多大?

    • SOCK_STREAM :这并不重要 . 如果您的协议是事务性/交互式协议,只需选择一个可以容纳您合理预期的最大单个消息/命令的大小(3000可能没问题) . 如果您的协议正在传输批量数据,那么更大的缓冲区可以更有效 - 一个好的经验法则与套接字的内核接收缓冲区大小(通常大约256kB)大致相同 .

    • SOCK_DGRAM :使用足够大的缓冲区来容纳应用程序级协议发送的最大数据包 . 如果你发送大于1400字节的数据包,因为它们肯定需要分段并重新组装 .

    如果 recv 获取的数据包大于缓冲区会发生什么?

    • SOCK_STREAM :这个问题没有't really make sense as put, because stream sockets don'这个数据包的概念 - 它们可以读取的字节多于缓冲区有空间,然后它们将被操作系统排队并可用于下次调用 recv .

    • SOCK_DGRAM :丢弃多余的字节 .

    我怎么知道我是否收到了整条信息?

    • SOCK_STREAM :您需要构建一些方法来确定应用程序级协议中的消息结束 . 通常,这是一个长度前缀(以消息的长度开始每个消息)或消息结束分隔符(例如,它可能只是基于文本的协议中的换行符) . 第三种较少使用的选项是为每条消息强制使用固定大小 . 这些选项的组合也是可能的 - 例如,包括长度值的固定大小的 Headers .

    • SOCK_DGRAM :单个 recv 调用始终返回单个数据报 .

    有没有办法让缓冲区没有固定的空间,这样我可以继续添加它而不用担心空间不足?

    不可以 . 但是,您可以尝试使用 realloc() (如果最初使用 malloc()calloc() 分配)来调整缓冲区的大小 .

  • 206

    对于TCP等流媒体协议,您几乎可以将缓冲区设置为任意大小 . 也就是说,建议使用常用值为2的幂,如4096或8192 .

    如果有更多的数据然后你的缓冲区,它将被简单地保存在内核中,以便下次调用 recv .

    是的,你可以继续增加你的缓冲区 . 你可以在offset idx 开始执行一个recv到缓冲区的中间,你可以这样做:

    recv(socket, recv_buffer + idx, recv_buffer_size - idx, 0);
    
  • 2

    如果你有一个 SOCK_STREAM 套接字, recv 只是从流中得到"up to the first 3000 bytes" . 关于缓冲区的大小没有明确的指导:只有当你知道一个流有多大时,它才会完成;-) .

    如果你有一个 SOCK_DGRAM 套接字,并且数据报大于缓冲区, recv 用数据报的第一部分填充缓冲区,返回-1,并将errno设置为EMSGSIZE . 不幸的是,如果协议是UDP,这意味着数据报的其余部分丢失 - 为什么UDP被称为 unreliable 协议的部分原因(我知道有可靠的数据报协议,但它们不是TCP / IP系列中的一个名称) ,尽管知道后者很好;-) .

    要动态增长缓冲区,最初使用 malloc 分配它,并根据需要使用 realloc . 但是这不会帮助你从UDP源获得 recv ,唉 .

  • -4

    对于 SOCK_STREAM 套接字,缓冲区大小并不重要,因为你只是拉出一些等待的字节,你可以在下次调用中检索更多 . 只需选择您能承受的任何缓冲区大小 .

    对于 SOCK_DGRAM 套接字,您将获得等待消息的拟合部分,其余部分将被丢弃 . 您可以使用以下ioctl获取等待数据报大小:

    #include <sys/ioctl.h>
    int size;
    ioctl(sockfd, FIONREAD, &size);
    

    或者,您可以使用 recv() 调用的 MSG_PEEKMSG_TRUNC 标志来获取等待的数据报大小 .

    ssize_t size = recv(sockfd, buf, len, MSG_PEEK | MSG_TRUNC);
    

    然后你可以只是 malloc() 缓冲区并检索数据报 .

  • 15

    您的问题没有绝对的答案,因为技术始终与特定于实现的方式相关 . 我假设您正在使用UDP进行通信,因为传入的缓冲区大小不会给TCP通信带来问题 .

    根据RFC 768,UDP的数据包大小(包括头)可以是8到65 515字节 . 因此,传入缓冲区的防故障大小将为65 507字节(~64KB)

    但是,并非所有大型数据包都可以通过网络设备正确路由,请参阅现有讨论以获取更多信息:

    What is the optimal size of a UDP packet for maximum throughput?
    What is the largest Safe UDP Packet Size on the Internet

  • 13

    16kb是正确的;如果你使用的是千兆以太网,每个数据包的大小可能是9kb .

相关问题