网络编程(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是表明该可选项是否支持可读或是可写。

levelOptnamegetset说明标志数据类型







SOL_SOCKETSO_BROADCASTyy允许发送广播数据报yint

SO_DEBUGyy使能调试跟踪yint

SO_DONTROUTEyy旁路路由表查询yint

SO_ERRORy
获取待处理错误并消除
int

SO_KEEPALIVEyy周期性测试连接是否存活yint

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

SO_OOBINLINEyy让接收到的带外数据继续在线存放yint

SO_RCVBUFyy接收缓冲区大小
int

SO_SNDBUFyy发送缓冲区大小
int

SO_RCVLOWATyy接收缓冲区低潮限度
int

SO_SNDLOWATyy发送缓冲区低潮限度
int

SO_RCVTIMEOyy接收超时
timeval{}

SO_SNDTIMEOyy发送超时
timeval{}

SO_REUSEADDRyy允许重用本地地址yint

SO_REUSEPORTyy允许重用本地地址yint

SO_TYPEy
取得套接口类型
int

SO_USELOOPBACKyy路由套接口取得所发送数据的拷贝yint







IPPROTO_IPIP_HDRINCLyyIP头部包括数据yint

IP_OPTIONSyyIP头部选项
见后面说明

IP_RECVDSTADDRyy返回目的IP地址yint

IP_RECVIFyy返回接收到的接口索引yint

IP_TOSyy服务类型和优先权
int

IP_TTLyy存活时间
int

IP_MULTICAST_IFyy指定外出接口
in_addr{}

IP_MULTICAST_TTLyy指定外出TTL
u_char

IP_MULTICAST_LOOPyy指定是否回馈
u_char

IP_ADD_MEMBERSHIP
y加入多播组
ip_mreq{}

IP_DROP_MEMBERSHIP
y离开多播组
ip_mreq{}







IPPROTO_ICMPV6ICMP6_FILTERyy指定传递的ICMPv6消息类型
icmp6_filter{}







IPPROTO_IPV6IPV6_ADDRFORMyy改变套接口的地址结构
int

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

IPV6_DSTOPTSyy接收目标选项yint

IPV6_HOPLIMITyy接收单播跳限yint

IPV6_HOPOPTSyy接收步跳选项yint

IPV6_NEXTHOPyy指定下一跳地址ysockaddr{}

IPV6_PKTINFOyy接收分组信息yint

IPV6_PKTOPTIONSyy指定分组选项
见后面说明

IPV6_RTHDRyy接收原路径yint

IPV6_UNICAST_HOPSyy缺省单播跳限
int

IPV6_MULTICAST_IFyy指定外出接口
in6_addr{}

IPV6_MULTICAST_HOPSyy指定外出跳限
u_int

IPV6_MULTICAST_LOOPyy指定是否回馈yu_int

IPV6_ADD_MEMBERSHIP
y加入多播组
ipv6_mreq{}

IPV6_DROP_MEMBERSHIP
y离开多播组
ipv6_mreq{}







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

TCP_MAXRTyyTCP最大重传时间
int

TCP_MAXSEGyyTCP最大分节大小
int

TCP_NODELAYyy禁止Nagle算法yint

TCP_STDURGyy紧急指针的解释yint

 

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

        

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

#include <sys/socket.h>
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 <sys/socket.h>
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<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>

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 git@github.com:HymanLiuTS/NetDevelopment.git

获取本文源代码:

git checkout NL09


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值