套接字的多种可选项

来源:互联网 发布:淘宝pc无线套餐搭配 编辑:程序博客网 时间:2024/05/21 08:36

套接字的可选项

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

             

                    从这个表可以看出,套接字的选项是分层的。IPPROTO_IP层可选项是IP协议相关事项,IPPROTO_TCP层可选项是TCP协议相关的事项,SOL_SOCKET层是套接字相关的通用可选项。


常见可选项:

1,协议层为SOL_SOCKET下的SO_TYPE可选项,可查看套接字的类型(TCP或UDP).

 

2,协议层为SOL_SOCKET下的SO_SNDBUF和SO_RCVBUF可选项,分别是可以设置输出缓冲和输入缓冲的大小(需要注意的是,缓冲区的大小不会完全按照我们的要求去设定)

 

3,协议层为SOL_SOCKET下的SO_REUSEADDR可选项,可以设置地址是否可以再分配。


查看和修改可选项的函数:

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


-------sock              用于查看选项套接字文件描述符。

-------level             要查看的可选项的协议层。

-------optname        要查看的可选项名。

-------optval           传递用于保存结果的变量的地址

-------optlen           传递保存有第四个变量长度的变量的地址


int setsockopt(int sock,int level,int optname,const void* optval,socklen_t  optlen);


-------sock              用于更改可选项的套接字文件描述符。

-------level             要更改的可选项协议层。

-------optname        要更改的可选项名。

-------optval           传递保存有要修改的值的变量地址

-------optlen          传递第四个参数的长度



示例代码:

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/socket.h>void error_handling(char *message);int main(int argc,char *argv[]){int tcp_sock,udp_sock;int sock_type;socklen_t optlen;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,(void*)&sock_type,&optlen);if(state)error_handling("getsocket() error!");printf("Socket type one: %d \n",sock_type);state = getsockopt(udp_sock,SOL_SOCKET,SO_TYPE,(void*)&sock_type,&optlen);if(state)error_handling("getsockopt() error!");printf("Socket type two: %d \n",sock_type);return 0;}void error_handling(char *message){fputs(message,stderr);fputc('\n',stderr);exit(1);


套接字类型的SO_TYPE是典型的只读可选项即: “套接字的类型只能在创建时决定,以后不能更改。”


Time_wait状体与地址再分配:

当客户端与服务器端通信完成后,服务器端先关闭时(即服务器端向客户端发送FIN消息),再次打开服务器端时,将会出现bind() error,这和TCP的四次握手有关,套接字经过四次握手过程后并非立即消除,而会经过一段时间的Time_wait状态(大约3分钟左右,保证对方收到此方发出去的应答消息二启动了一个Time_wait计时器),只有先断开连接(谁先发送FIN消息)的主机才经过Time_wait状态,因为Time_wait的状态,相应的端口依旧被占用,所以bind()会出错

注意:

1、无论是服务器端还是客户端都有Time_wait状态,先断开连接的套接字必然经过Time_wait过程,却无需考虑客户端的Time_wait状态,因为客户端套接字的端口号是动态分配的

2、当先断开连接的套接字进入Time_wait状态时(发送回复对方FIN的ACK时进入Time_wait状态),一旦ACK发送失败,当再次接收到对方的FIN时(对方认为自己发送过来的消息没有发送成功时重传的)将重启计时器,再次进入Time_wait状态

不一定全是优点的Time_wait状态

Time_wait状态其实在有些时候是不合理的存在,如系统发生故障从而紧急停止的情况,这时需要尽快重启服务器,但因处于Time_wait状态而不得不等待。可以通过可选项SO_REUSEADDR来修改在Time-wait状态下端口号是否可以重新分配给新套接字,从而解决这个问题。SO_REUSEADDR的默认值为0(假),将其修改为1(真)。

//加在调用bind()之前 int option = TRUE;socklen_t optlen = sizeof(option); setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &option, optlen);

Nagle算法

 

1、防止因数据包过多而发生网络过载

2、只有接收到对前一数据的ACK消息时,才发送下一数据,未收到ACK消息时最大限度的进行缓冲,当收到ACK消息后将缓冲的数据一并发出

3、传输速度比不使用Nagle算法时低,但是传输效率更高

 

启用Nagle算法时,未收到ACK不继续发,而未启用Nagle时不依靠是否接收ACK消息来判断能否继续发送下一数据,即数据到达输出缓冲后立即被发出去,若写一字节停一下停写一字节的方式写入输出缓冲区,由于未使用Nagle算法,算上发送的数据与对方的ACK一共需要字节数 * 2 个数据包!!!!!!!,而且数据包头信息可能有几十字节,这明显不是一桩划算的买卖

 

Nagle算法也不是什么时候都适用,最典型的就是”传输大文件数据”,将文件数据传入输处缓冲区比较快,即便不使用Nagle算法也会在装满输出缓冲时传输数据包,这样不仅不增加数据包数量,而且还无需等待ACK可连续传输,可大大提高传输速度

 

禁用方法:

int opt_val = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&opt_val, sizeof(opt_val));








0 0
原创粉丝点击