socket编程中套接字缓冲区大小的问题

时间:2021-10-27 11:07:38
一直对socket编程中的套接字缓冲区的大小等有关知识感觉很模糊,今天在网上看到这么一段话:
如果套接字sockfd的发送缓冲区中没有数据或者数据被协议成功发送完毕后,recv先检查套接字sockfd的接收缓冲区,如果sockfd的接收缓冲区中没有数据或者协议正在接收数据,那么recv就一起等待,直到把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲区中的数据copy到buff中(注意协议接收到的数据可能大于buff的长度,所以在这种情况下要调用几次recv函数才能把sockfd的接收缓冲区中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的)”

recv函数:ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);

这段话中提到协议接收到的数据如果大于buff的长度,就需要调用多次recv才能把接收缓冲区的数据copy完,但如果我们要recv的数据长度nbytes大于缓冲区的长度(也就是协议接收到的数据)时,那么recv又该怎么做?

26 个解决方案

#1


buff 指的就是 recv的第二个参数, 而不是recv内部还有一个buff.

#2


1:可以用setsockopt设置fd缓冲区大小
2:循环接收数据,知道接收长度为length为止。

#3


引用 1 楼 lgbxyz 的回复:
buff 指的就是 recv的第二个参数, 而不是recv内部还有一个buff.

是的,但如果recv的第三个参数nbytes远远大于接收缓冲区的长度,这时recv是读满一个缓冲区长度的数据就返回吗?还是阻塞在那里一定要读到nbytes长度的数据才返回?(假定第四个参数为0)

#4


引用 2 楼 clearwwu 的回复:
1:可以用setsockopt设置fd缓冲区大小
2:循环接收数据,知道接收长度为length为止。

设置fd的缓冲区大小是不是会对提升传输速度有影响?

#5


引用 3 楼 hhhlizhao 的回复:
Quote: 引用 1 楼 lgbxyz 的回复:

buff 指的就是 recv的第二个参数, 而不是recv内部还有一个buff.

是的,但如果recv的第三个参数nbytes远远大于接收缓冲区的长度,这时recv是读满一个缓冲区长度的数据就返回吗?还是阻塞在那里一定要读到nbytes长度的数据才返回?(假定第四个参数为0)


有多少读多少,读到的字节数就是其返回值

#6


是的,但如果recv的第三个参数nbytes远远大于接收缓冲区的长度,这时recv是读满一个缓冲区长度的数据就返回吗?还是阻塞在那里一定要读到nbytes长度的数据才返回?(假定第四个参数为0)

有多少读多少,读到的字节数就是其返回值

我们在write或recv时都是用的循环的方式,我试了一下write 500M的数据一次循环就可成功,如果是recv的话,一次可以recv多少呢?

#7


buff空了就返回了,不会读满nbytees,tcp的send/recv 等价于 read/write。
你都做了各种尝试了,试一下不就明确了吗

#8


引用 7 楼 lgbxyz 的回复:
buff空了就返回了,不会读满nbytees,tcp的send/recv 等价于 read/write。
你都做了各种尝试了,试一下不就明确了吗

试了一下一次recv 500M好像会出现错误。
还有,你这里的buff 是指recv的第二参数,还是内核缓冲区?

#9


自然是内核buff空了,recv声明的buff只能填充不能清空啊

#10


引用 9 楼 lgbxyz 的回复:
自然是内核buff空了,recv声明的buff只能填充不能清空啊

内核buff空了会返回,如果读到nbytes字节的数据,而内核buff还没有空,这时也会返回的吧?

#11


当然会返回,要不然要循环干什么     

#12


引用 11 楼 lgbxyz 的回复:
当然会返回,要不然要循环干什么     

还有一个问题想请教大神,如果想提高socket文件传输的效率,都有什么方法?

#13


这个你得具体需求具体分析,增大buff(内核或者传入buff)都是 空间换时间。
多路复用也能提高并发性能。

#14


引用 13 楼 lgbxyz 的回复:
这个你得具体需求具体分析,增大buff(内核或者传入buff)都是 空间换时间。
多路复用也能提高并发性能。

我是点对点的传输,一个server,一个client,现在想通过千兆网线传输数据,但传输速度太慢达不到要求。
我尝试增大发送端(client)的发送缓冲区大小为1024*1000,接收端的接收缓冲区增大为1024*10000,但传输速度提升的十分有限,几乎没有效果,这是什么原因?是大小设置的不对吗?

#15


首先你得先确定一下 server 和 client 之间的速率, 比如server上搭建一个http server,使用http下载需要多少时间,
通常来说你的实现应该小于http下载的时间。
光增大buff对高并发会有明显提示,你只是单个实例自然看不出提升。

如果速率慢 可以考虑多线程下载。

#16


引用 15 楼 lgbxyz 的回复:
首先你得先确定一下 server 和 client 之间的速率, 比如server上搭建一个http server,使用http下载需要多少时间,
通常来说你的实现应该小于http下载的时间。
光增大buff对高并发会有明显提示,你只是单个实例自然看不出提升。

如果速率慢 可以考虑多线程下载。

那单对单的连接传输速度应该怎么提升?我的server和client都是自己写的程序,基于TCP传输,而且也应该用不到多线程。

#17


如果你的程序没有问题, 只能通过多线程/进程 解决。
通常是先通信获取需要下载文件的大小, 然后起多线程 每个下载 其中一部分。

#18


引用 17 楼 lgbxyz 的回复:
如果你的程序没有问题, 只能通过多线程/进程 解决。
通常是先通信获取需要下载文件的大小, 然后起多线程 每个下载 其中一部分。

在我的下位机程序(client)中,我用了一次mmap,之后没有用memcpy拷贝内存,而是直接用write将mmap之后的数据写入到sockfd中,不知道 时间是不是浪费在了这里?直接write和memcpy之后再write进sockfd哪个更快点?

#19


没看明白, 你到底是要上传还是下载?

可以把要发送的文件mmap到内存,会提升,但是对点对点通信而言不会明显。

除非你的程序有重大bug,否则简单的TCP通信不会性能慢的问题,你还是先确认一下带宽吧。

#20


引用 19 楼 lgbxyz 的回复:
没看明白, 你到底是要上传还是下载?

可以把要发送的文件mmap到内存,会提升,但是对点对点通信而言不会明显。

除非你的程序有重大bug,否则简单的TCP通信不会性能慢的问题,你还是先确认一下带宽吧。

我是在下位机先mmap,之后将被mmap地址的数据write到sockfd传到上位机(server),中间没有使用memcpy这一api,这样速度会降低吗?

#21


速度不会下降,只会比读文件快。
不用mmap,也用不到 memcpy。

#22


引用 21 楼 lgbxyz 的回复:
速度不会下降,只会比读文件快。
不用mmap,也用不到 memcpy。

我这个比较特殊,必须要用到mmap,之后再将被mmap内存中的数据write到sockfd中。这中间没有用到memcpy。

#23


引用 21 楼 lgbxyz 的回复:
速度不会下降,只会比读文件快。
不用mmap,也用不到 memcpy。

再请教您一个问题,我今天看到一篇文章,上面讲socket也可以使用mmap,但讲的好像是基于UDP协议的数据包,不知道基于TCP的字节流可不可以用这种方式实现?

http://blog.csdn.net/ruixj/article/details/4153118

#24


那里是用来做sinffer(嗅探工具)的, 拿到的是原始包,除非你想自己在写一套协议栈处理数据.

#25


引用 24 楼 lgbxyz 的回复:
那里是用来做sinffer(嗅探工具)的, 拿到的是原始包,除非你想自己在写一套协议栈处理数据.

那这种方式可以用来传输传输字节流数据吗?如果可以需要对原始包在应用层做什么处理?

#26


sniffer 只是把正常协议栈中数据copy一份用来分析.

#1


buff 指的就是 recv的第二个参数, 而不是recv内部还有一个buff.

#2


1:可以用setsockopt设置fd缓冲区大小
2:循环接收数据,知道接收长度为length为止。

#3


引用 1 楼 lgbxyz 的回复:
buff 指的就是 recv的第二个参数, 而不是recv内部还有一个buff.

是的,但如果recv的第三个参数nbytes远远大于接收缓冲区的长度,这时recv是读满一个缓冲区长度的数据就返回吗?还是阻塞在那里一定要读到nbytes长度的数据才返回?(假定第四个参数为0)

#4


引用 2 楼 clearwwu 的回复:
1:可以用setsockopt设置fd缓冲区大小
2:循环接收数据,知道接收长度为length为止。

设置fd的缓冲区大小是不是会对提升传输速度有影响?

#5


引用 3 楼 hhhlizhao 的回复:
Quote: 引用 1 楼 lgbxyz 的回复:

buff 指的就是 recv的第二个参数, 而不是recv内部还有一个buff.

是的,但如果recv的第三个参数nbytes远远大于接收缓冲区的长度,这时recv是读满一个缓冲区长度的数据就返回吗?还是阻塞在那里一定要读到nbytes长度的数据才返回?(假定第四个参数为0)


有多少读多少,读到的字节数就是其返回值

#6


是的,但如果recv的第三个参数nbytes远远大于接收缓冲区的长度,这时recv是读满一个缓冲区长度的数据就返回吗?还是阻塞在那里一定要读到nbytes长度的数据才返回?(假定第四个参数为0)

有多少读多少,读到的字节数就是其返回值

我们在write或recv时都是用的循环的方式,我试了一下write 500M的数据一次循环就可成功,如果是recv的话,一次可以recv多少呢?

#7


buff空了就返回了,不会读满nbytees,tcp的send/recv 等价于 read/write。
你都做了各种尝试了,试一下不就明确了吗

#8


引用 7 楼 lgbxyz 的回复:
buff空了就返回了,不会读满nbytees,tcp的send/recv 等价于 read/write。
你都做了各种尝试了,试一下不就明确了吗

试了一下一次recv 500M好像会出现错误。
还有,你这里的buff 是指recv的第二参数,还是内核缓冲区?

#9


自然是内核buff空了,recv声明的buff只能填充不能清空啊

#10


引用 9 楼 lgbxyz 的回复:
自然是内核buff空了,recv声明的buff只能填充不能清空啊

内核buff空了会返回,如果读到nbytes字节的数据,而内核buff还没有空,这时也会返回的吧?

#11


当然会返回,要不然要循环干什么     

#12


引用 11 楼 lgbxyz 的回复:
当然会返回,要不然要循环干什么     

还有一个问题想请教大神,如果想提高socket文件传输的效率,都有什么方法?

#13


这个你得具体需求具体分析,增大buff(内核或者传入buff)都是 空间换时间。
多路复用也能提高并发性能。

#14


引用 13 楼 lgbxyz 的回复:
这个你得具体需求具体分析,增大buff(内核或者传入buff)都是 空间换时间。
多路复用也能提高并发性能。

我是点对点的传输,一个server,一个client,现在想通过千兆网线传输数据,但传输速度太慢达不到要求。
我尝试增大发送端(client)的发送缓冲区大小为1024*1000,接收端的接收缓冲区增大为1024*10000,但传输速度提升的十分有限,几乎没有效果,这是什么原因?是大小设置的不对吗?

#15


首先你得先确定一下 server 和 client 之间的速率, 比如server上搭建一个http server,使用http下载需要多少时间,
通常来说你的实现应该小于http下载的时间。
光增大buff对高并发会有明显提示,你只是单个实例自然看不出提升。

如果速率慢 可以考虑多线程下载。

#16


引用 15 楼 lgbxyz 的回复:
首先你得先确定一下 server 和 client 之间的速率, 比如server上搭建一个http server,使用http下载需要多少时间,
通常来说你的实现应该小于http下载的时间。
光增大buff对高并发会有明显提示,你只是单个实例自然看不出提升。

如果速率慢 可以考虑多线程下载。

那单对单的连接传输速度应该怎么提升?我的server和client都是自己写的程序,基于TCP传输,而且也应该用不到多线程。

#17


如果你的程序没有问题, 只能通过多线程/进程 解决。
通常是先通信获取需要下载文件的大小, 然后起多线程 每个下载 其中一部分。

#18


引用 17 楼 lgbxyz 的回复:
如果你的程序没有问题, 只能通过多线程/进程 解决。
通常是先通信获取需要下载文件的大小, 然后起多线程 每个下载 其中一部分。

在我的下位机程序(client)中,我用了一次mmap,之后没有用memcpy拷贝内存,而是直接用write将mmap之后的数据写入到sockfd中,不知道 时间是不是浪费在了这里?直接write和memcpy之后再write进sockfd哪个更快点?

#19


没看明白, 你到底是要上传还是下载?

可以把要发送的文件mmap到内存,会提升,但是对点对点通信而言不会明显。

除非你的程序有重大bug,否则简单的TCP通信不会性能慢的问题,你还是先确认一下带宽吧。

#20


引用 19 楼 lgbxyz 的回复:
没看明白, 你到底是要上传还是下载?

可以把要发送的文件mmap到内存,会提升,但是对点对点通信而言不会明显。

除非你的程序有重大bug,否则简单的TCP通信不会性能慢的问题,你还是先确认一下带宽吧。

我是在下位机先mmap,之后将被mmap地址的数据write到sockfd传到上位机(server),中间没有使用memcpy这一api,这样速度会降低吗?

#21


速度不会下降,只会比读文件快。
不用mmap,也用不到 memcpy。

#22


引用 21 楼 lgbxyz 的回复:
速度不会下降,只会比读文件快。
不用mmap,也用不到 memcpy。

我这个比较特殊,必须要用到mmap,之后再将被mmap内存中的数据write到sockfd中。这中间没有用到memcpy。

#23


引用 21 楼 lgbxyz 的回复:
速度不会下降,只会比读文件快。
不用mmap,也用不到 memcpy。

再请教您一个问题,我今天看到一篇文章,上面讲socket也可以使用mmap,但讲的好像是基于UDP协议的数据包,不知道基于TCP的字节流可不可以用这种方式实现?

http://blog.csdn.net/ruixj/article/details/4153118

#24


那里是用来做sinffer(嗅探工具)的, 拿到的是原始包,除非你想自己在写一套协议栈处理数据.

#25


引用 24 楼 lgbxyz 的回复:
那里是用来做sinffer(嗅探工具)的, 拿到的是原始包,除非你想自己在写一套协议栈处理数据.

那这种方式可以用来传输传输字节流数据吗?如果可以需要对原始包在应用层做什么处理?

#26


sniffer 只是把正常协议栈中数据copy一份用来分析.