这一章的难点是理解每个参数的物理意义。
一边问google一边问百度,感觉有些理解了,但又有些模糊。
真是纸上得来终觉浅,绝知此事要躬行。
不管怎么样,先简单了解下。
接口:
#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int s,
int level,
int optname,
const void* optval,
socklen_t *optlen);
int setsockopt(int s,
int level,
int optname,
const void* optval,
socklen_t optlen);
Level 与 Option Name
SOL_SOCKET SO_REUSEADDR
SOL_SOCKET SO_KEEPALIVE
SOL_SOCKET SO_LINGER
SOL_SOCKET SO_BROADCAST
SOL_SOCKET SO_OOBINLINE
SOL_SOCKET SO_SNDBUF
SOL_SOCKET SO_RCVBUF
SOL_SOCKET SO_TYPE
SOL_SOCKET SO_ERROR
SOL_TCP SO_NODELAY
详细解释:
SO_SNDBUF 控制发送端缓冲区大小。
SO_RCVBUF 控制接收端缓冲区大小
注意:
1> 设置值必须满足一个 最大值与最小值, 本地写代码测试后发现是[256, 4* 1024* 1024]
查看文档,发现最大值是下面2个内核参数控制:
/proc/sys/net/core/rmem_max r:read 接收端
/proc/sys/net/core/wmem_max w:write 发送端
进一步可以执行:获取3个值 最小值 默认值 最大值
cat /proc/sys/net/ipv4/tcp_wmem
cat /proc/sys/net/ipv4/tcp_rmem
UDP的话,是下面3个: (意思还不是很明确)
cat /proc/sys/net/ipv4/udp_mem
cat /proc/sys/net/ipv4/udp_rmem_min
cat /proc/sys/net/ipv4/udp_wmem_min
2> 在这个区间内,获取值为设置值的2倍。即调用set(10000)后,get返回值为20000.
核心问题:
多大合适?客户端、服务器端?UDP还是TCP?网络规模?并发连接数?
要回答这个问题,可能还是需要在实际项目中做性能测试才能回答。
SO_TYPE 获取socket类型
查看内核代码,可知道其枚举定义如下:
enum sock_type {
SOCK_STREAM = 1,
SOCK_DGRAM = 2,
SOCK_RAW = 3,
SOCK_RDM = 4,
SOCK_SEQPACKET= 5,
SOCK_DCCP = 6,
SOCK_PACKET = 10,
};
SO_REUSEADDR
解决SOCKET的复用问题。
问题:
回到前面11章,Server端调用fork启动子进程,子进程会继续使用同一个socket与client端连接。
如果Server端崩溃后再启动,调用listen函数来监听同一个socket(IP,Port),系统会返回EADDRINUSE。
为了解决这个问题,Server端在调用listen函数之前,必须设置SO_REUSEADDR为TRUE。
注意:该选项只对TCP有效。
SO_LINGER
查了下字典,linger在英语中是徘徊的意思。
设置这个选项后,调用close时,系统会阻塞一段时间(由SO_LINGER设置),再返回。
设置参数:
struct linger {
int l_onoff; //开关选项
int l_linger; //等待时间,以秒为单位
};
这个选项我的感觉并不是太好,一遇到Timeout,便引发了驱动编程里面的经典问题:
Timeout到底设置为多大? 理论依据有吗?
其实,很多情况下都是一个经验值。这个值可靠吗?大多数情况下都是天知道。
通常应该设置为>=2 MSL (不过遗憾的是MSL是动态变化的。)
SO_KEEPALIVE
这个选项的物理意义就是系统每2个小时定时发送探测消息(probe)。
条件:2小时内双方无数据交互
触发动作:给对方发送探测消息
反馈消息处理:
状态1:对方接收一切正常:以期望的ACK响应。
状态2:对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口本身则被关闭。
状态3:对方无任何响应:11分钟内系统会多次发送探测消息。如果大约11分钟内,无回应,则套接口的待处理错误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。
相关参数:
/proc/sys/net/ipv4/tcp_keepalive_time 默认值75s
/proc/sys/net/ipv4/tcp_keepalive_probes 默认值9 (9*75 = 大约11分钟15秒)
/proc/sys/net/ipv4/tcp_keepalive_time 默认值7200 (2小时)
SO_BROADCAST
启动组播支持
主要:设置的socket必须支持组播,否则无效
SO_OOBINLINE
OOB是Out of band data的缩写,意思是该消息比较紧急,需要马上处理。
该选项的实际意义是在TCP流里引入了优先队列的概念。
SO_PASSCRED与SO_PEERCRED
只支持本地socket,CRED代表数字身份验证
阅读过Android代码的,可以发现Android在property机制中使用了该选项。
进一步查看linux内核可以发现,还有IP层等其他协议的option设置。