套接字选项
一、相关方法
1、getsockopt 和 setsockopt 函数
#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);
均返回:成功为0,出错为-1
2、fcntl 函数
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
典型的设置socket阻塞、非阻塞的案例
if((flags = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("F_GETFL error");
flags |= O_NONBLOCK; //设置为非阻塞
// flags &= ~O_NONBLOCK; //设置为阻塞
if(fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
iotcl函数
二、选择说明 level值、optname值
level值一般有:SOL_SOCKET,IPPROTO_IP,IPPROTO_ICMPV6,IPPROTO_IPV6,IPPROTO_TCP,IPPROTO_SCTP。重点关注:SOL_SOCKET,IPPROTO_IP,IPPROTO_TCP
1、SOL_SOCKET
通用的套接字选项
选项名 | 说明 | 数据类型 |
---|---|---|
SO_BROADCAST | 允许发送广播数据 | int |
SO_DEBUG | 允许调试 | int |
SO_DONTROUTE | 不查找路由 | int |
SO_ERROR | 获得套接字错误 | int |
SO_KEEPALIVE | 保持连接 | int |
SO_LINGER | 延迟关闭连接 | struct linger |
SO_OOBINLINE | 带外数据放入正常数据流 | int |
SO_RCVBUF | 接收缓冲区大小 | int |
SO_SNDBUF | 发送缓冲区大小 | int |
SO_RCVLOWAT | 接收缓冲区下限 | int |
SO_SNDLOWAT | 发送缓冲区下限 | int |
SO_RCVTIMEO | 接收超时 | struct timeval |
SO_SNDTIMEO | 发送超时 | struct timeval |
SO_REUSERADDR | 允许重用本地地址和端口 | int |
SO_TYPE | 获得套接字类型 | int |
SO_BSDCOMPAT | 与BSD系统兼容 | int |
重点选项说明:
(1) SO_DONTROUTE
设置该选项要求源和目的主机在同一网络或端对端可达,即不经过路由。
(2) SO_KEEPALIVE
主要是为服务端主机起作用,为未关闭的TCP连接提供2小时一次的心跳检测。主要针对客户端主机崩溃或者不可达(即主机都来不及发出最后一个FIN结束信号),这种情况下如果套接字未设置SO_KEEPALIVE,则服务端一直监听并占用socket,浪费资源。
(3) SO_LINGER
设置socket调用close() 关闭套接字的时,距离真正关闭套接字的逗留时间。缺省的close()行为:如果有数据残留在socket发送缓冲区中,则系统将继续发送这些数据给对方,等待被确认,然后发送FIN关闭套接字。
SO_LINGER选项用来改变此缺省设置。使用如下结构:
struct linger {
int l_onoff; /* 0 = off, nozero = on */
int l_linger; /* linger time */
};
有下列三种情况:
- 设置 l_onoff 为0,则该选项关闭,l_linger 的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;
- 设置 l_onoff 为非0,l_linger 为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;
- 设置 l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完成。
(4) SO_REUSERADDR
允许两种情况下绑定“相同”的IP:PORT对,
- 地址通配符 ‘0.0.0.0’ 与任一具体的本地地址 不相冲突;
- 处于TIME_WAIT状态的IP:PORT对,可以被再次成功绑定
SO_REUSEPORT 允许将任意数目的socket绑定到完全相同的 IP:PORT 对上,前提条件是所有绑定这个IP:PORT 对的socket都设置了SO_REUSEPORT选项。另外绑定了相同IP:PORT对的socket必须去connect不同的远端IP:PORT,否则会得到EADDRINUSE错误。
2、IPPROTO_IP
针对ip协议的套接字选项
选项名 | 说明 | 数据类型 |
---|---|---|
IP_HDRINCL | 在数据包中包含IP首部 | int |
IP_OPTINOS | IP首部选项 | int |
IP_RECVDSTADDR | 返回目的IP地址 | int |
IP_RECVIF | 返回接收接口索引 | int |
IP_TOS | 服务类型 | int |
IP_TTL | 生存时间 | int |
3、IPPROTO_TCP
针对tcp协议的套接字选项
选项名 | 说明 | 数据类型 |
---|---|---|
TCP_MAXSEG | TCP最大数据段的大小 | int |
TCP_NODELAY | 不使用Nagle算法 | int |
Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段. 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到.
Nagle算法的规则(可参考tcp_output.c文件里tcp_nagle_check函数注释):
(1)如果包长度达到MSS,则允许发送;
(2)如果该包含有FIN,则允许发送;
(3)设置了TCP_NODELAY选项,则允许发送;
(4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
(5)上述条件都未满足,但发生了超时(一般为200ms),则立即发送.
默认情况下,发送数据采用Nagle算法.这样虽然提高了网络吞吐量,但是实时性却降低了,在一些交互性很强的应用程序来说是不允许的,使用TCP_NODELAY选项可以禁止Nagle 算法.此时,应用程序向内核递交的每个数据包都会立即发送出去.需要注意的是,虽然禁止了Nagle 算法,但网络的传输仍然受到TCP确认延迟机制的影响.