UNIX网络编程 TCP套接字选项

时间:2022-11-07 11:01:02

一直想写一下TCP通信的事,
套接字选项:
SO_DEBUG:当给一个TCP套接字开启本选项时, 内核将为TCP在该套接字发送和接收的所有分组保留详细跟踪信息。
SO_DONTROUTE:本选项规定外出的分组将绕过底层协议的正常路由机制。
SO_KEEPALIVE:本选项的功用是检测对端主机是否崩溃或变得不可达。
这个选项非常有用。什么是心跳机制

心跳机制就是当客户端与服务端建立连接后,每隔几分钟发送一个固定消息给服务端,服务端收到后回复一个固定消息给客户端,如果服务端几分钟内没有收到客户端消息,则视客户端断开。发送方可以是客户端和服务端,看具体需求。
为什么要使用
我们都知道在TCP这种长连接情况下下,有可能有一大段时间是没有数据往来的,即处于空闲状态。理论上说,这个连接是一直保持连接的,但是在实际应用中,如果中间节点出现什么故障是难以预测的。更可怕的是,有的节点会自动把一定时间之内没有数据交互的连接切断。所以,需要我们利用心跳机制,来维持长连接,保活通信。
实现方法
应用层: 由应用程序自己每隔一定时间向客户/服务端发送一个短小的数据包,然后启动一个线程,在线程中不断检测客户端的回应, 如果在一定时间内没有收到客户/服务端的回应,即认为客户/服务端已经掉线,连接不可用。
设置SO_KEEPALIVE套接字选项:在TCP通信中,存在heartbeat机制。其实就是TCP的选项。当服务/客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。
注意:因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不默认开启KeepAlive。KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多应用程序来说,空闲时间太长。因此,我们可以手工开启KeepAlive功能并设置合理的KeepAlive参数。

SO_LINGER :顾名思义是延迟延缓的意思,这里是延缓面向连接的socket的close操作。
close函数默认操作是立即返回.但是如果有数据残留在套接字发送缓冲区中,系统将试着把这些数据发送给对端。
控制SO_LINGER通过下面一个结构:
struct linger
{
int l_onoff; /0=off, nonzero=on/
int l_linger; /linger time, POSIX specifies units as seconds/
};
通过结构体中成员的不同赋值,可以表现为下面几种情况:
1. l_onoff设置为0,选项被关闭。l_linger值被忽略,就是上面的默认情形,close立即返回。
2. l_onoff设置为非0,l_linger被设置为0,则close()不被阻塞立即执行,丢弃socket发送缓冲区中的数据,并向对端发送一个RST报文。
这种关闭方式称为“强制”或“失效”关闭。
3. l_onoff设置为非0,l_linger被设置为非0,则close()调用阻塞进程,直到所剩数据发送完毕或超时。

//Setting For KeepAlive
int keepalive = 1;
setsockopt(incomingsock,SOL_SOCKET,SO_KEEPALIVE,(void*)(&keepalive),(socklen_t)sizeof(keepalive));
int keepalive_time = 30;
setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPIDLE,(void*)(&keepalive_time),(socklen_t)sizeof(keepalive_time));
int keepalive_intvl = 3;
setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPINTVL,(void*)(&keepalive_intvl),(socklen_t)sizeof(keepalive_intvl));
int keepalive_probes= 3;
setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPCNT,(void*)(&keepalive_probes),(socklen_t)sizeof(keepalive_probes));

SO_OOBINLINE:
SO_RCVBUF:设置接收缓冲区的默认大小。TCP的窗口规模选项是在建立连接时用SYN分节与对端互换得到的。对于客户,必须在调用connect之前设置,对于服务器 ,必须在调用listen之前给监听套接字设置。
SO_RCVLOWAT: 接收缓冲区低水位标记, 是让select返回“可读”时套接字接收缓冲区中所需的数据量, 默认值为1。
SO_SNDBUF:设置发送缓冲区的默认大小。
SO_SNDLOWAT:发送缓冲区低水位标记, 是让select返回“可写”时套接字接收缓冲区中所需的数据量, 默认值为2048。
TCP_MAXSEG:本选项允许我们获取或设置TCP连接的最大分节大小(MSS);
SO_RESUEADDR: 一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使主要有四个方面的作用:
1. 允许一个监听服务器到,bind到现在使用的端口上,即使之前存服务端口的连接存在
例如: (1)启动服务端口:45001,该端口处于listen状态
(2)有一个客户端连接到该端口上,可以派生子进程 来处理该链 路
(3)关闭监听端口,但是步骤2中的链路存在
(4)重新启动监听端口45001
步骤(4)在socket后执行bind的时候会报错“Address already in use”,如果该进程在socket之后和bind之前设置了SO_REUSEADDR,bind将会成功。

  1. 允许不同的进程bind到同一个机器上相同端口不同IP地址上
    例如:主机上有两个IP地址,172.17.252.81 172.17.252.82 172.17.252.83
    进程A可以bind IP:172.17.252.81 端口:45001 (用netstat看时,172.17.252.81.45001)
    进程B可以bind IP:172.17.252.82 端口:45001 (用netstat看时,172.17.252.82.45001)
    进程C可以bind IP:统配地址 端口:45001 (用netstat看时,*.45001)
    当有客户端请求时,按照最适合的原则,比如客户端connect时指定的IP:172.17.252.81则有进程A处理该服务
    如果没有启动进程A和B,客户端connect时指定的IP:172.17.252.81则有进程C处理该服务
    该情况可能存在风险,对于特权端口,我们都不能bind成功
    对于非特权端口,比如45001,主机上有多个IP地址,采用了统配IP来处理客户的请求,我们可以启动bind具体IP的服务端口,来
    处理客户端的请求,对于应用来说是比较危险的。

3.允许同一个进程bind到同一个机器相同端口不同IP的地址上,与情况2类似

4.允许完全重复的bind,端口和IP相同,此时需要传输协议的支持,一般只支持UDP

SO_REUSEPORT:
1.该选项允许完全的绑定,IP和端口可以完全一样,每个socket都必须制定该选项
2.如果多播地址,与SO_RESUEADDR含义相同
TCP_NODELAY: 当有一个TCP数据段不足MSS,比如要发送700Byte数据,MSS为1460Byte的情况。nagle算法会延迟这个数据段的发送,等待,直到有足够的数据填充成一个完整数据段

参考:
Linux socket编程的心跳机制总结 - 博客频道 - CSDN.NET http://blog.csdn.net/u011192270/article/details/47621771