获取和设置套接字选项
在进行网络编程时,经常需要查看或设置套接字的某些特性,例如设置地址复用,读写数据的超时时间,对读缓冲区的大小进行调整等操作。获取套接字选项的设置情况的函数是getsockopt(),设置套接字选项的函数为setsockopt().这两个函数在调整网络的性能和功能方面起着重要的作用。
1. getsockopt和setsockopt函数的介绍
getsockopt和setsockopt函数原型如下所示:
#include<sys/types.h> #include<sys/socket.h> int getsockopt(int s,int level,int optname,void *optval,socklen_t *optlen); int setsockopt(int s,int level,int optname,const void *optval, socklen_t optlen);
getsockopt和setsockopt的函数定义如下所述:
- s: 将要获取或设置的套接字描述符,可以通过socket函数获得。
- level:选项所在的协议层。支持的层次有支持的层次有SOL_SOCKET(通用套接字选项)、IPPROTO_TCP(TCP选项),IPPROTO_IP(IP选项)。为了操作套接字层的选项,应该将该层的值设置为SOL_SOCKET.
- optname: 选项名。 套接字层用的比较多的选项如SO_RCVBUF(表示接收缓冲区的大小),SO_SNDBUF(表示发送缓冲区的大小)。
- optval:操作的内存缓冲区。对于getsockopt函数,指向用于获取返回选项值的缓冲区。对于setsockopt函数,指向设置的参数缓冲区。
- optlen: 第四个参数的长度。对于getsockopt函数而言,是一个指向socket_t类型的指针,当用于传入的参数时,表示传入optval的实际长度;当用于传出参数时,表示用于保存optval的最大长度。对于setsockopt函数,optlen表示第四个参数的实际长度。
2. 套接字选项
按照参数选项级别level值的不同,套接字选项大致可以分为一下3类:
- 通用套接字选项:参数level的值为SOL_SOCKET,用于获取或者设置通用的一些参数,例如接收和发送的缓冲区大小,地址重用(这个设置在服务器程序中经常使用,关于通用套接字的用法,可以参考UNP 7.5小节)等。通用套接字选项是协议无关的。
- IP选项: 参数level的值为IPPROTO_IP,用于设置或者获取IP层的参数。选项名为IP_HDRINCL表示在数据中包含IP头部数据,IP_TOS表示服务类型,IP_TTL表示存活时间等。
- TCP选项:参数level的值为IPPRPTP_TCP,用于获得或者设置TCP 协议层的一些参数。例如选项名TCP_MAXRT对最大重传时间进行操作,选项名TCP_MAXSEG对最大分片大小进行操作,选项名TCP_KEEPALIVE对保持连接时间进行操作。
3. 代码示例
系统提供的socket缓冲区大小为8K,你可以将之设置为64K,尤其在传输实时视频时。
socket发送数据时候先把数据发送到socket缓冲区中,之后接受函数再从缓冲区中取数据,如果发送端特别快的时候,缓冲区很快就被填满 (socket默认的是1024×8=8192字节),这时候我们应该根据情况设置缓冲区的大小,可以通过setsockopt函数实现
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <assert.h> int main(int argc,char **argv) { int err = -1; /* 返回值 */ int s = -1; /* socket描述符 */ int snd_size = 0; /* 发送缓冲区大小 */ int rcv_size = 0; /* 接收缓冲区大小 */ socklen_t optlen; /* 选项值长度 */ /* * 建立一个TCP套接字 */ s = socket(PF_INET,SOCK_STREAM,0); if( s == -1){ printf("建立套接字错误 "); return -1; } /* * 先读取缓冲区设置的情况 * 获得原始发送缓冲区大小 */ optlen = sizeof(snd_size); err = getsockopt(s, SOL_SOCKET, SO_SNDBUF,&snd_size, &optlen); if(err<0){ printf("获取发送缓冲区大小错误 "); } /* * 打印原始缓冲区设置情况 */ /* * 获得原始接收缓冲区大小 */ optlen = sizeof(rcv_size); err = getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); if(err<0){ printf("获取接收缓冲区大小错误 "); } printf(" 发送缓冲区原始大小为: %d 字节 ",snd_size); printf(" 接收缓冲区原始大小为: %d 字节 ",rcv_size); /* * 设置发送缓冲区大小 */ snd_size = 10*1024; /* 发送缓冲区大小为8K */ optlen = sizeof(snd_size); err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &snd_size, optlen); if(err<0){ printf("设置发送缓冲区大小错误 "); } /* * 设置接收缓冲区大小 */ rcv_size = 10*1024; /* 接收缓冲区大小为8K */ optlen = sizeof(rcv_size); err = setsockopt(s,SOL_SOCKET,SO_RCVBUF, (char *)&rcv_size, optlen); if(err<0){ printf("设置接收缓冲区大小错误 "); } /* * 检查上述缓冲区设置的情况 * 获得修改后发送缓冲区大小 */ optlen = sizeof(snd_size); err = getsockopt(s, SOL_SOCKET, SO_SNDBUF,&snd_size, &optlen); if(err<0){ printf("获取发送缓冲区大小错误 "); } /* * 获得修改后接收缓冲区大小 */ optlen = sizeof(rcv_size); err = getsockopt(s, SOL_SOCKET, SO_RCVBUF,(char *)&rcv_size, &optlen); if(err<0){ printf("获取接收缓冲区大小错误 "); } /* * 打印结果 */ printf(" 发送缓冲区大小为: %d 字节 ",snd_size); printf(" 接收缓冲区大小为: %d 字节 ",rcv_size); close(s); return 0; }
运行后的结果如下所示:
从结果 看出ubuntu系统默认的发送缓冲区大小:16384字节,接收缓冲区87380字节
但是有个问题我设置的接收和发送缓冲区大小为:10*1024=10240字节,但是实际用getoptsock得到却是20480字节加了一倍。改成其他大小也是都是加倍。
这是由linux内核的算法决定的。
参考链接: