影响套接字选项的函数
getsockop 和 setsockop函数 fcntl ioctl
getsockopt 和 setsockopt
//其中sockfd必须指向一个打开套接字描述符,level(级别)指定系统中解释选项的代码或 //为通/用套接字代码,或为某个特定于协议的代码,optval是一个指向某个变量(*optval) //的指针,setsockopt从*optval中取得选项待设置的新值,getsockopt则把已获取的 //选项当前值存放到*optval,*optval的大小由最后一个参数optlen指定, //它对于setsockopt是一个值参数,对于getsockopt是一个值-结果参数 #include <sys/socket.h> int getsockop(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);
fcntl函数
//非阻塞I/O。通过使用F_SETFL命令设置O_NONBLOCK文件状态标志,我们可以把一个套接字 // 设置为非阻塞型 //信号驱动I/O。通过使用F_SETFL命令设置O_ASYNC文件状态标志,我们可以把一个套接字设 // 置成一旦其状态发生变化,内核就产生一个SIGIO信号 //F_SETOWN命令允许我们指定用于接收SIGIO和SIGURG信号的进程ID或进程组ID,。其中 // SIGIO信号是套接字被设置为信号驱动式I/O型后产生的,SIGURG信号是在新的外带数据 // 到达套接字时产生的。 //每种描述符(包括套接字描述符)都有一组由F_GETFL命令获取或F_SETFL命令设置 //的文件标志。其中影响套接字描述符的两个标志是: //O_NONBLOCK--------非阻塞I/O //O_ASYNC-------------信号驱动式I/O #include<fcntl.h> int fcntl(int fd, int cmd, ... /* int arg */ );
套接字层和IP层的选项汇总
通用套接字选项
SO_BROADCAST
本选项开启或禁用发送广播消息能力。只有数据报套接字支持广播,并且还必须是在支持广播消息的网络上(如以太网,令牌环网等)。我们不可以在点对点链路上进行广播,也不能在基于连接的传输协议上进行广播
SO_DEBUG
本选项仅支持TCP,当给一个TCP套接字开启本选项时,内核将为TCP在该套接字发送和接收时的所有分组保留详细跟踪信息。这些信息保存在内核的某个环形缓冲区中,并可使用trpt程序进行检查
SO_DONTROUTE
本选项规定外出的分组将绕过底层的正常路由机制
SO_ERROR
当一个套接字上发生错误时,来自伯里克的内核中的协议模块将该套接字的名为so_error的变量设置为标志的unix Exxx值中的一个,我们称它为该套接字的待处理错误。内核能够以下面两种方式之一立即通知这个错误
1)如果进程阻塞在该套接字的select调用上,那么无论是检查可读条件还是可写条件,select均返回并设置其中一个或所有两个条件
2)如果进程使用信号驱动式I/O模型,那就给进程或进程组产生一个SIGIO信号
SO_KEEPALIVE
给一个TCP套接字设置keepalive选项后,如果两小时内在该套接字的任一方向上都没有数据交换,TCP就自动给对端发送一个keepalive探测分组,这是一个对端必须响应的TCP分组,它会导致以下三种情况
1)对端以期望的ACK响应,应用进程得不到通知(因为一切正常)。在经过无动静的2小时后TCP将发出另一个探测分组
2)对端以RST响应,它告知本端TCP,对端已崩溃且已重新启动。该套接字的待处理错误被设置为ECONNRESET,套接字本身则被关闭
3)对端保持存货探测分组没有任何响应,来自伯里克的TCP将另外发送8个探测分组,两两相隔75秒,试图得到一个响应,TCP在发出第一个探测分组后11分15秒内若没有得到任何响应则放弃
SO_LINGER
本选项指定close函数对面连接的协议如何操作,默认操作是close立即返回,但是如果有数据残留在套接字发送缓冲区中,系统将逝者把这些数据发送给对方
so_linger的结构如下
#include <sys/socket.h> struct linger { int l_onoff; int l_linger }
1)如果 l_onoff为0那么关闭该选项,l_linger被忽略,先前讨论的TCP默认设置生效,close立即返回
2)如果l_onoff为非0且l_linger为0,那么当close某个连接时TCP将终止该连接。也就是说TCP将丢弃保留在
套接字发送缓冲区中的任何数据,并发送给对方一个RST,而且没有四次握手的断开序列,这么一来可以
避免TIME_WAIT状态,这也可能导致新连接是旧连接的化神(端口一样)
3)如果l_onoff为非0值且l_linger也为非0值,那么当套接字关闭时内核将拖延一段时间,如果套接字发送
缓冲区中仍残留数据,那么进行将被设置为休眠,直到a)所有数据都发送完并且对方确认 b)延迟时间到
如果套接字被设置为非阻塞型,那么将不等待close完成,即使延迟时间为非0也是如此
如果调用的是shutdown函数
1)如果是关闭读请求,那么套接字不再接收任何数据,接收缓冲区的数据将被丢弃,但对写缓冲区无影响
2)如果是关闭写请求,套接字发送缓冲区中的内容发送到对端后,再发送FIN,对读无任何影响
SO_OOBINLINE
开启本选项时,带外数据将被流量在正常输入队里中
SO_RCVBUF和SO_SNDBUF
套接字的发送和棘手缓冲区,这个值是在建立连接时用SYN互换得到的
所以客户端必须在connect函数调用之前设置,服务端必须在listen函数调用前设置
TCP接收缓冲区大小应该是连接的MSS的四倍大小
SO_RCVLOWAT和SO_SNDLOWAT
每个套接字还有一个接收低水位标记和一个发送低水位标记
低水位标记是让select返回可读时套接字接收缓冲区中所需的数量,对于UDP和TCP默认是1
发送低水位标记让select返回可写时套接字发送缓冲区中所需的可用空间,对于TCP默认是2048
SO_RCVTIMEO和SO_SNDTIMEO
这两个选项允许我们给套接字的接收和发送设置一个超时值
接收超时影响的五个函数
read,readv,recv,recvfrom和recvmsg
发送超时影响的五个函数
write,writev,send,sendto,sendmsg
SO_REUSEADDR和SO_REUSEPORT
有如下一些作用
1)SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将该端口用作他们的
本地端口连接仍然存在
2)允许在同一端口上启动同一服务器的多个实例,比如一个机器有多个IP
3)允许单个进程捆绑同一端口到多个套机子上,只要每次捆绑指定不同的本地IP地址即可
4)SO_REUSEADDR允许完全重复的捆绑
SO_TYPE
本选项返回套接字的类型,返回的整数是一个诸如SOCK_STREAM或SOCK_DGRAM之类的值
SO_USELOOPBACK
本选项仅用于路由域(AF_ROUTE)套接字
IPv4套接字选项
IP_HDRINCL
如果本选项是给一个原始IP套接字设置的,那么我们必须为所在该原始套接字上发送数据报构造自己的IP首部,一般情况下载原始套接字上发送的数据报其IP首部是由内核构造的,不过有些应用程序(特别是traceroute)需要构造自己的IP首部以取代IP置于该首部中的某些字段
当本选项开启时,我们构造完整的IP首部,不过下列情况列外
1)IP总是计算并存储IP首部校验和
2)如果我们将IP标识字段置为0,内核将设置该字段
3)如果源IP地址是INADDR_ANY,IP将把它设置为外出接口的主IP地址
4)如何设置IP选项取决于实现
5)IP首部中有些字段必须以主机字节序列填写,有些字段必须以网络字节序填写
IP_OPTIONS
本选项的设置允许我们在IPv4首部中设置IP选项,这要求我们熟悉IP首部中IP选项的格式
IP_RECVDSTADDR
本套接字选项导致所收到UDP数据报的目的IP地址由recvmsg函数作为辅助数据返回
IP_RECVIF
本套机子选项导致所收到UDP数据报的接收接口索引由recvmsg函数作为辅助数据返回
IP_TOS
本套接字选项允许我们为TCP,UDP或STCP套接字设置IP首部中的服务类型字段
IP_TTL
我们可以使用本选项设置或获取系统用在某个给定套接字发送的单播分组上默认TTL值
TCP套接字选项
TCP_MAXSEG
允许我们获取或设置TCP连接的最大分组大小MSS,返回值是我们的TCP可以发送给对端的最大数据量,它通常是由对端使用SYN分组通告的MSS,除非我们的TCP选择使用一个比对端通告的MSS小些的值
TCP_NODELAY
开启本选项将禁用TCP的nagle算法,默认情况下算法是启动的
算法的目的在于减少广域网上小分组的数目
nagle算法常与另一个TCP算法联合使用,ACK延迟算法,该算法使得TCP在接收到数据后不立即发送ACK而是等待一小时间(50--200ms)
举例,假设客户端发送400字节的请求,先发送4字节的头再发送396字节的消息体、那么第二个写操作数据将一直等到服务器的TCP确认了第一个写操作的4字节后才由客户端TCP发送出去。服务端在收到4字节后仍然等待396字节的消息体,一直等待于是ACK延迟发送超时(等了一段时间才发送ACK)
有三种办法修正这个客户程序
1)使用writev,而不是两次调用write,单个writev调用最终导致TCP输出功能一次而不是两次,其结果是产生
一个TCP分组
2)把前面4个字节和后面396字节的数据复制到单个缓冲区中,然后对该缓冲区调用一次write
3)设置TCP_NODELAY套接字选项,继续调用wirte两次,这是最不可取的办法
参考
UNP总结 Chapter 7 套接字选项
LINUX下getsockopt和setsockopt函数