C语言程序开发中,网络通信库函数recv函数,究竟应该传递多大的内存给它?

和其他编程语言一样,C语言程序开发中也是有许多好用的库函数的,借助这些库函数,C语言程序员能够较为简单的开发出各种有用的程序。

例如C语言中的 socket 库允许程序员进行 TCP/IP 通信编程,要使用该库仅需包含相应的头文件,再调用相应的库函数即可,无需关心庞大繁杂的 TCP/IP 协议栈。以 recv() 函数为例,它的C语言原型如下,请看:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

读者应注意 recv() 函数的第二个参数 buffer,它是用于从 TCP/IP 通信缓冲区接收数据的内存段。作为C语言程序员,这里有一个敏感点:调用 recv() 函数时,分配给 buffer 的内存应该多大呢?

如果分配给 buffer 的内存过小,则当缓冲区的数据长度较长时,容易造成内存溢出或者数据截断的风险。如果分配给 buffer 的内存过大,则又会造成浪费。况且,到底多大算“过大”呢?

那么,能否让 buffer 动态改变大小呢?如果缓冲区内的数据很长,则将 buffer 分配大一点,否则就分配小一点。遗憾的是,一般我们并不能事先得知缓冲区内的数据长度。而C语言也不支持动态类型,传递给 recv() 函数的 buffer 内存只能是事先分配好的固定大小内存。

虽然,C语言有 realloc() 这样的库函数用于重新分配内存大小,但是recv() 函数是已经封装好的,对程序员不可见,我们不能指望 recv() 函数一定会自己根据数据长度重新分配合适大小的内存。所以,在使用 socket 库时,应该弄清楚以下几个问题:

  1. 怎样确定 recv() 函数的参数 buffer 长度?
  2. 如果 recv() 函数的 buffer 长度小于缓冲区实际的数据长度会发生什么?
  3. 怎样确定 recv() 函数是否已经将缓冲区内的数据完全取出?

要回答以上几个问题,首先应该弄清楚的是当前正在使用的究竟是流 (stream)socket 还是数据报(datagram) socket。(一般来说,TCP 通信一般使用流 socket,而 UDP 通信一般使用数据报 socket。)

那么,recv() 函数用于接收数据的 buffer 参数究竟应该设置多大呢?

对于流 socket,buffer 的大小并不是特别重要,因为数据都是流式传输的,就通信协议本身而言,“数据并没有大小之分”,因此 buffer 的大小设置为实际项目需要的最大的单个消息/命令大小就可以了,简言之,就是什么大小方便,就设置成什么样的大小即可。

不过要是数据报 socket,就不能这样做了,此时应该使用足够大的 buffer 来保存应用程序级协议锁发送的最大数据报。如果当前使用的是 UDP 通信,那么一般来说,应用程序级协议不应该发送大于 1400 字节的数据包,因为过长的数据报肯定会被拆分成若干个小段分别发送。

如果 recv() 函数的 buffer 长度小于缓冲区实际的数据长度会发生什么?

对于流 socket,这个问题稍显奇怪。因为正如前文所述,谈论数据流的大小是没有意义的,数据流仅仅只是连续的字节流而已。如果 buffer 长度小于缓冲区实际的数据长度,那么 recv() 函数仅会将 buffer 填满,然后返回。缓冲区内剩余的数据可以再调用 recv() 函数得到。

不过对于数据报 socket,超出的数据就会被丢弃了。

怎样才能知道是否已经将缓冲区内实际的数据全部取出了呢?

如果使用的是流 socket,显然,仅根据 socket 通信本身,是无法得知是否已经完全接受数据。此时,需要程序员在应用程序级协议中自定义某种确定消息结尾的方法,比如一段特殊的字节序列,或者数据开头的几个用于描述总体数据长度的字节等等。

对于数据报 socket,每次调用 recv() 函数,总是返回一个完整的数据报。

小结

到这里相信读者应该明白C语言程序开发中使用 socket 库关于 recv() 函数 buffer 参数长度的基本原理了。到底有没有一种方法让 buffer 的长度随着缓冲区内数据长度动态改变呢?答案是否定的,对于C语言程序开发,我们最多能够使用 realloc() 函数重新分配 buffer 的大小。

https://stackoverflow.com/questions/2862071/how-large-should-my-recv-buffer-be-when-calling-recv-in-the-socket-library

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif