一、linux下怎么获取tcp发送缓冲区还有多少空闲
int getsockopt(int sockfd, int level, int optname, void*optval, socklen_t*optlen);
参数
sockfd:一个标识套接口的描述字。
level:选项定义的层次。支持的层次仅有SOL_SOCKET和IPPROTO_TCP。
optname:需获取的套接口选项。
optval:指针,指向存放所获得选项值的缓冲区。
optlen:指针,指向optval缓冲区的长度值。
返回值:
若无错误发生,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缓冲区大小的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。