×

【Linux】深入理解缓冲区_linux缓冲区

前端技术网 前端技术网 发表于2024-01-18 07:39:45 浏览3151 评论0

抢沙发发表评论

一、linux下怎么获取tcp发送缓冲区还有多少空闲

int getsockopt(int sockfd, int level, int optname, void*optval, socklen_t*optlen);

参数

【Linux】深入理解缓冲区_linux缓冲区

sockfd:一个标识套接口的描述字。

level:选项定义的层次。支持的层次仅有SOL_SOCKET和IPPROTO_TCP。

optname:需获取的套接口选项。

optval:指针,指向存放所获得选项值的缓冲区。

optlen:指针,指向optval缓冲区的长度值。

返回值:

【Linux】深入理解缓冲区_linux缓冲区

若无错误发生,getsockopt()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

错误代码:

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。

WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。

WSAEFAULT:optlen参数非法。

WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。

WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM类型的套接口不支持SO_ACCEPTCONN、SO_DONTLINGER、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。

WSAENOTSOCK:描述字不是一个套接口。

注释:

编辑

getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval。在不同协议层上存在选项,但往往是在最高的“套接口”层次上,设置选项影响套接口的操作,诸如操作的阻塞与否、包的选径方式、带外数据的传送等。

被选中选项的值放在optval缓冲区中。optlen所指向的整形数在初始时包含缓冲区的长度,在调用返回时被置为实际值的长度。对SO_LINGER选项而言,相当于linger结构的大小,对其他选项来说,是一个整形数的大小。

如果未进行setsockopt()调用,则getsockopt()返回系统缺省值。

getsockopt()支持下列选项。其中“类型”栏指出了optval所指向的值。仅有TCP_NODELAY选项使用了IPPROTO_TCP层;其余选项均使用SOL_SOCKET层。

选项类型意义

SO_ACCEPTCONN BOOL套接口正在用listen()监听。

SO_BROADCAST BOOL套接口设置为传送广播信息。

SO_DEBUG BOOL允许调试。

SO_DONTLINER BOOL若为真,则SO_LINGER选项被禁止。

SO_DONTROUTE BOOL禁止选径。

SO_ERROR int获取错误状态并清除。

SO_KEEPALIVE BOOL发送“保持活动”信息。

SO_LINGER struct linger FAR*返回当前各linger选项。

SO_OOBINLINE BOOL在普通数据流中接收带外数据。

SO_RCVBUF int接收缓冲区大小。

SO_REUSEADDR BOOL套接口能和一个已在使用中的地址捆绑。

SO_SNDBUF int发送缓冲区大小。

SO_TYPE int套接口类型(如SOCK_STREAM)。

TCP_NODELAY BOOL禁止发送合并的Nagle算法。

getsockopt()不支持的BSD选项有:

选项名类型意义

SO_RCVLOWAT int接收低级水印。

SO_RCVTIMEO int接收超时。

SO_SNDLOWAT int发送低级水印。

SO_SNDTIMEO int发送超时。

IP_OPTIONS获取IP头中选项。

TCP_MAXSEG int获取TCP最大段的长度。

用一个未被支持的选项去调用getsockopt()将会返回一个WSAENOPROTOOPT错误代码(可用WSAGetLastError()获取)。

二、修改linux系统socket缓冲区大小

进行socket编程有时候可能需要修改下socket的接收缓冲区大小,这里可以使用 setsockopt函数,但是如果需要修改的缓冲区很大(比如500MB),则还需要修改系统内核的TCP/IP参数,不然接收缓冲区大小会收到内核参数的限制,所以需要改两个地方。下面以把socket接收缓冲区修改为500MB说明一下要作的修改。《Linux就该这么学》

修改内核TCP/IP参数

在终端用sysctl命令修改socket最大缓冲区限制:

sudo sysctl-w net.core.rmem_max=5242880001

在代码中用setsockopt函数修改SO_RCVBUF选项

int recvbuff= 500*1024*1024;

if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,(const char*)&recvbuff, sizeof(int))==-1)

printf("setsocket error\n");

else

printf("setsocket success\n");12345

以上两点,只改第1点,一个socket只会预留63个报文的接收缓冲;只改第2点,缓冲区大小会受到rmem_max的限制,如果需要的缓冲区很大的话,必须两点都改。

三、Linux如何清空Socket缓冲区

socket不是这么接收数据的由于socket是以数据流的形式发送数据,接收方不知道对方一次性发送了多少数据,也能保证对方一次性发送的数据能在同一刻接收到,所以Receive方法是这么工作的:接受一个byye[]类型的参数作为缓冲区,在经过一定的时间后把接收到的数据填充到这个缓冲区里面,并且返回实际接收到数据的长度,这个实际接收到的数据长度有可能为0(没有接收到数据)、大于0小于缓冲区的长度(接收到数据,但是没有我们预期的多)、等于缓冲区的长度(说明接收到的数据大于等于我们预期的长度)。每次接收缓冲区都用同一个byte[] byteMessage,并且你没有检查接收到的数据长度,所以第一次你接收到的数据是123456,第二次你只接收到了8,但是缓冲区里面还有23456,所以加起来就是823456了。 socket接收缓冲区的大小有讲究,设置大了接收起来慢,因为它要等尽可能多的数据接收到了再返回;设置小了需要重复多次调用接收方法才能把数据接收完,socket有个属性,标识了系统默认的接收缓冲区大小,可以参考这个!还有就是用recv读取,但是由于不知道缓存里有多少数据,如果是阻塞模式,到最后必然等到超时才知道数据已经读取完毕,这是个问题。另一个是用fgetc,通过返回判断是否是feof: whlie(1){ a=fgetc(f);if(feof(f)) break;//… b=fgetc(f);if(feof(f)) break;//…}当然,我不知道读取完毕后最后一次调用fgetc会不会堵塞,需要测试。在非阻塞模式下,我们用recv就可以轻松搞定了,但是阻塞模式下,由于我们不知道缓冲区有多少数据,不能直接调用recv尝试清除。使用一个小小的技巧,利用select函数,我们可以轻松搞定这个问题: select函数用于监视一个文件描述符**,如果**中的描述符没有变化,则一直阻塞在这里,直到超时时间到达;在超时时间内,一旦某个描述符触发了你所关心的事件,select立即返回,通过检索文件描述符**处理相应事件;select函数出错则返回小于零的值,如果有事件触发,则返回触发事件的描述符个数;如果超时,返回0,即没有数据可读。重点在于:我们可以用select的超时特性,将超时时间设置为0,通过检测select的返回值,就可以判断缓冲是否被清空。通过这个技巧,使一个阻塞的socket成了‘非阻塞’socket.现在就可以得出解决方案了:使用select函数来监视要清空的socket描述符,并把超时时间设置为0,每次读取一个字节然后丢弃(或者按照业务需要进行处理,随你便了),一旦select返回0,说明缓冲区没数据了(“超时”了)。 struct timeval tmOut;tmOut.tv_sec= 0;tmOut.tv_usec= 0;fd_set fds;FD_ZEROS(&fds);FD_SET(skt,&fds); int nRet; char tmp[2]; memset(tmp, 0, sizeof(tmp)); while(1){ nRet= select(FD_SETSIZE,&fds, NULL, NULL,&tmOut);if(nRet== 0) break;recv(skt, tmp, 1,0);}这种方式的好处是,不再需要用recv、recvfrom等阻塞函数直接去读取,而是使用select,利用其超时特性检测缓冲区是否为空来判断是否有数据,有数据时才调用recv进行清除。有人说同样可以用recv和socket的超时设置去清空啊,这个没错,但是你需要直接对socket描述符设置超时时间,而为了清空数据而直接修改socket描述符的属性,可能会影响到其他地方的使用,造成系统奇奇怪怪的问题,所以,不推荐使用。

四、请教Linux关于UDP最大缓冲区设置

1. tcp收发缓冲区默认值 [root@ ]# cat/proc/sys/net/ipv4/tcp_rmem 4096 87380 4161536 87380:tcp接收缓冲区的默认值 [root@ ]# cat/proc/sys/net/ipv4/tcp_wmem 4096 16384 4161536 16384: tcp发送缓冲区的默认值 2. tcp或udp收发缓冲区最大值 [root@ ]# cat/proc/sys/net/core/rmem_max 131071 131071:tcp或 udp接收缓冲区最大可设置值的一半。也就是说调用 setsockopt(s, SOL_SOCKET, SO_RCVBUF,&rcv_size,&optlen);时rcv_size如果超过 131071,那么 getsockopt(s, SOL_SOCKET, SO_RCVBUF,&rcv_size,&optlen);去到的值就等于 131071* 2= 262142 [root@ ]# cat/proc/sys/net/core/wmem_max 131071 131071:tcp或 udp发送缓冲区最大可设置值得一半。跟上面同一个道理 3. udp收发缓冲区默认值 [root@ ]# cat/proc/sys/net/core/rmem_default 111616:udp接收缓冲区的默认值 [root@ ]# cat/proc/sys/net/core/wmem_default 111616 111616:udp发送缓冲区的默认值 4. tcp或udp收发缓冲区最小值 tcp或udp接收缓冲区的最小值为 256 bytes,由内核的宏决定; tcp或udp发送缓冲区的最小值为 2048 bytes,由内核的宏决定

关于【Linux】深入理解缓冲区_linux缓冲区和修改linux系统socket缓冲区大小的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。