#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
通用套接字选项:
1、SO_BROADCAST
允许和禁止进程发送广播消息的能力,广播仅能用于UDP。如果UDP进程用一个广播地址作为目的地址,但是该选项为开启,那么返回EACCES错误,是不会发送广播消息的。
2、SO_KEEPALIVE
允许套接字每隔2小时发送探测分节,这个分节对端必须给予响应。本端发送探测分节,会遇到如下3种情况:
- 正常情况,对端发送ack响应,这种情况对于应用层是透明的,应用层是没有感知的;
- 对端崩溃并已经重启,对端响应RST,待处理错误被设置为ECONNRESET,套接字关闭;
- 对端掉电或崩溃或网络不可达,对端无响应,本端超时重传8个分节,超时则设置ETIMEOUT,收到ICMP错误消息,则设置EHOSTUNREACH。
对于本选项常见问题是修改发送周期2小时,需要修改内核,但是要注意的是,如果内核被修改,则这台机器上的所有套接字,均采用此周期时间。
本选项对于探测对端是否崩溃,是否掉线非常有效,如果对端已经出现问题,本端则处于半连接的状态,浪费系统资源。
3、SO_LINGER
struct linger {
int l_onoff; // 0=off nonzero=on
int l_linger; // linger time(second)
}
- 如果为未设置SO_LINGER,默认操作是close直接返回,但是如果发送缓冲区有数据会尝试将数据发送给对端
- 如果l_onoff为非零,l_linger为零,close中止该TCP连接,丢弃发送缓冲区数据,并发送RST消息给对端
- 如果l_onoff为非零,l_linger为非零,如果发送缓冲区有数据,2种情况close返回,1)则将等待l_linger时间后,超时,close返回,2)当然如果l_linger时间之前数据已经发送完毕(注意,这个发送完毕,确切说是收到对端的ack,数据确认),close返回。如果等待l_linger时间后发送缓冲区种还有数据(确切说未收到对端的数据确认ack消息)则close返回EWOULDBLOCK错误。
close具体返回时机看下面3个图:
总结:设置了l_linger,close成功返回,先前发送的数据和FIN消息,已由对端TCP确认,而不是应用层已经成功读取数据。不过通过对l_linger和shutdown的讨论,不禁要想,对于一般的网络应用,确认对端是否已经收到消息,并不是非常重要,所以一般的close就可以满足要求。同时设置l_onoff=1,l_linger=0,有特殊应用,如果探测网络已经有问题,比如应用层发现发送超时或其它异常,则直接丢弃发送和接收缓冲区数据,RST到对端,连接终止非常干净。
4、SO_RCVBUF SO_SNDBUF
对于接收缓冲区的设置必须在listen和accept之前。
TCP套接字选项
1、TCP_NODELAY
开启本选项,是为了禁止TCP的Nagle算法,该算法目的是为了减少网络上小分节数据的数量,它会将多个小分节数据合并到一个分节进行发送,以减少网络负载,同时Nagle算法常常和ACK延滞算法放到一起执行,也就是说不单独发送ACK消息,而是当有数据发送时,由当前数据捎带过去。
从这个图中可以看出,如果服务器发送小字节,并且需要客户端已最快的速度回响应ack,则需要禁止Nagle算法,通常采用TCP_NODELAY选项则是一个好选择