套接字的多种可选项

套接字的可选项

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

             

                    从这个表可以看出,套接字的选项是分层的。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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值