网络编程(9)—— 怎么获取和设置socket的输出\输入缓冲等多种可选项

一、关于套接字的可选项        

        套接字中可以设置和获取多种可选项,包括套接字的类型(TCP套接字还是UDP套接字)、接收和发送缓冲区的大小等等。下图就是套接字中支持的可选项:

        level是可选项的分层,SOL_SOCKE是socket级别(对应应用层)的可选项,其中我们常用的设置输入/输出缓冲区的大小(SO_RCVBUF和SO_SNDBUF)就在该层;PPROTO_TCP是TCP/UDP级别(对应传输层)的可选项的设置,我们可以进行Nagle算法的开启或者关闭等等;IPPROTO_IP、IPPROTO_IPV6和IPPROTO_ICMPV6对应于网络层的选项的设置,只不过分别用于ip4、ip6、icmpv6等协议相关的设置。

Optname是设置的可选项的名称。而get和set是表明该可选项是否支持可读或是可写。

level Optname get set 说明 标志 数据类型







SOL_SOCKET SO_BROADCAST y y 允许发送广播数据报 y int

SO_DEBUG y y 使能调试跟踪 y int

SO_DONTROUTE y y 旁路路由表查询 y int

SO_ERROR y
获取待处理错误并消除
int

SO_KEEPALIVE y y 周期性测试连接是否存活 y int

SO_LINGER y y 若有数据待发送则延迟关闭
linger{}

SO_OOBINLINE y y 让接收到的带外数据继续在线存放 y int

SO_RCVBUF y y 接收缓冲区大小
int

SO_SNDBUF y y 发送缓冲区大小
int

SO_RCVLOWAT y y 接收缓冲区低潮限度
int

SO_SNDLOWAT y y 发送缓冲区低潮限度
int

SO_RCVTIMEO y y 接收超时
timeval{}

SO_SNDTIMEO y y 发送超时
timeval{}

SO_REUSEADDR y y 允许重用本地地址 y int

SO_REUSEPORT y y 允许重用本地地址 y int

SO_TYPE y
取得套接口类型
int

SO_USELOOPBACK y y 路由套接口取得所发送数据的拷贝 y int







IPPROTO_IP IP_HDRINCL y y IP头部包括数据 y int

IP_OPTIONS y y IP头部选项
见后面说明

IP_RECVDSTADDR y y 返回目的IP地址 y int

IP_RECVIF y y 返回接收到的接口索引 y int

IP_TOS y y 服务类型和优先权
int

IP_TTL y y 存活时间
int

IP_MULTICAST_IF y y 指定外出接口
in_addr{}

IP_MULTICAST_TTL y y 指定外出TTL
u_char

IP_MULTICAST_LOOP y y 指定是否回馈
u_char

IP_ADD_MEMBERSHIP
y 加入多播组
ip_mreq{}

IP_DROP_MEMBERSHIP
y 离开多播组
ip_mreq{}







IPPROTO_ICMPV6 ICMP6_FILTER y y 指定传递的ICMPv6消息类型
icmp6_filter{}







IPPROTO_IPV6 IPV6_ADDRFORM y y 改变套接口的地址结构
int

IPV6_CHECKSUM y y 原始套接口的校验和字段偏移
int

IPV6_DSTOPTS y y 接收目标选项 y int

IPV6_HOPLIMIT y y 接收单播跳限 y int

IPV6_HOPOPTS y y 接收步跳选项 y int

IPV6_NEXTHOP y y 指定下一跳地址 y sockaddr{}

IPV6_PKTINFO y y 接收分组信息 y int

IPV6_PKTOPTIONS y y 指定分组选项
见后面说明

IPV6_RTHDR y y 接收原路径 y int

IPV6_UNICAST_HOPS y y 缺省单播跳限
int

IPV6_MULTICAST_IF y y 指定外出接口
in6_addr{}

IPV6_MULTICAST_HOPS y y 指定外出跳限
u_int

IPV6_MULTICAST_LOOP y y 指定是否回馈 y u_int

IPV6_ADD_MEMBERSHIP
y 加入多播组
ipv6_mreq{}

IPV6_DROP_MEMBERSHIP
y 离开多播组
ipv6_mreq{}







IPPROTO_TCP TCP_KEEPALIVE y y 控测对方是否存活前连接闲置秒数
int

TCP_MAXRT y y TCP最大重传时间
int

TCP_MAXSEG y y TCP最大分节大小
int

TCP_NODELAY y y 禁止Nagle算法 y int

TCP_STDURG y y 紧急指针的解释 y int

 

二、利用getsockopt 和 setsockopt  进行可选项的获取和设置

        

        我们可以利用getsockopt和setsockopt进行套接字的可选项信息的获取和设置。他们的原型如下:

#include 
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
sockfd,socket描述符。
level,协议层(可选SOL_SOCKET、IPPROTO_IP、IPPROTO_TCP等)
optname,选项名,如SO_SNDBUF表示输出缓冲区,SO_TYPE表示socket的类型。
optval,保存查看结果的缓冲地址值
optlen,接收optval传递的缓冲大小的地址值

#include 
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);

sockfd,socket描述符
level,协议层(可选SOL_SOCKET、IPPROTO_IP、IPPROTO_TCP)
optname,选项名,如SO_SNDBUF表示输出缓冲区,SO_TYPE表示socket的类型。
optval,保存查看结果的缓冲地址值
optlen,optval传递的缓冲大小


下面是一个使用getsockopt和setsockopt的例子,例子中先获取了套接字的类型(是SOCK_STREAM还是SOCK_DGRAM),然后设置接收和发送缓冲区的大小,最后显示这些大小:

#include
#include
#include
#include

void error_handling(char* message);

int main(int argc,char* argv)
{
    //声明socket
    int tcp_sock,udp_sock;
    //socket类型
    int sock_type;
    //socket缓冲区大小
    int snd_buf,rev_buf;
    //可选项字节数
    socklen_t optlen;
    //getsockopt返回的状态,0表示获取成功
    int state;
    
    optlen=sizeof(sock_type);
    tcp_sock=socket(PF_INET,SOCK_STREAM,0);
    udp_sock=socket(PF_INET,SOCK_DGRAM,0);
    printf("SOCK_STREAM: %d\n",SOCK_STREAM);
    printf("SOCK_DGRAM: %d\n",SOCK_DGRAM);

    state=getsockopt(tcp_sock,SOL_SOCKET,SO_TYPE,&sock_type,&optlen);
    if(state)
        error_handling("getsockopt one error");
    printf("socket type one: %d\n",sock_type);

    state=getsockopt(udp_sock,SOL_SOCKET,SO_TYPE,&sock_type,&optlen);
    if(state)
        error_handling("getsockopt two error");
    printf("socket type two: %d\n",sock_type);

    optlen=sizeof(snd_buf);
    state=getsockopt(tcp_sock,SOL_SOCKET,SO_SNDBUF,&snd_buf,&optlen);
    if(state==0)
        printf("socket输出缓冲区大小是: %d\n",snd_buf);
    optlen=sizeof(rev_buf);
    state=getsockopt(tcp_sock,SOL_SOCKET,SO_RCVBUF,&rev_buf,&optlen);
    if(state==0)
        printf("socket输入缓冲区大小是: %d\n",rev_buf);

    printf("更改输入和输出缓冲区...\n");

    snd_buf=1024*3;
    rev_buf=1024*6;

    optlen=sizeof(snd_buf);
    state=setsockopt(tcp_sock,SOL_SOCKET,SO_SNDBUF,&snd_buf,optlen);
    if(state==0)
    {
        state=getsockopt(tcp_sock,SOL_SOCKET,SO_SNDBUF,&snd_buf,&optlen);
        printf("更改成功!\n");
        printf("更改后的输出缓冲区大小为:%d\n",snd_buf);
    }
    optlen=sizeof(rev_buf);
    state=setsockopt(tcp_sock,SOL_SOCKET,SO_RCVBUF,&rev_buf,optlen);
    if(state==0)
    {
        state=getsockopt(tcp_sock,SOL_SOCKET,SO_RCVBUF,&rev_buf,&optlen);
        printf("更改后的输入缓冲区大小为:%d\n",rev_buf);
    }
    return 0;
}

void error_handling(char* message)
{
    fputs(message,stderr);
    fputc('\n',stderr);
    exit(1);
}

        运行结果:

[Hyman@Hyman-PC csdn]$ ./a.out 
SOCK_STREAM: 1
SOCK_DGRAM: 2
socket type one: 1
socket type two: 2
socket输出缓冲区大小是: 16384
socket输入缓冲区大小是: 87380
更改输入和输出缓冲区...
更改成功!
更改后的输出缓冲区大小为:6144
更改后的输入缓冲区大小为:12288

        可能有部分童鞋对于结果有些疑问:

“为什么我设置的输入和输出缓冲区大小为1024*6和1024*3,实际设置成功的结果却是12288和6144?”

其实我们设置的值是操作系统设置socket输入和输出缓冲区的一个参考值,因为操作系统还要进行一些额外的操作:比如错误重传机制等等都需要一定的缓存,此时实际设置的值往往比我们预期的要大。这里只是为了演示,在实际的开发中socket默认的输出和输入缓冲已经足够我们使用了。。


Github位置:

https://github.com/HymanLiuTS/NetDevelopment

克隆本项目:

git clone [email protected]:HymanLiuTS/NetDevelopment.git

获取本文源代码:

git checkout NL09


你可能感兴趣的:(网络通信编程,网络通信编程)