套接字选项粗分为两大基本类型:
一是启用或禁止某个特性的二元选项(称为标志选项),
二是取得并返回我们可以设置或检查的特定值的选项(称为值选项)
SOL_SOCKET
下面的套接字选项是由TCP已连接套接字从监听套接字继承来的:
SO_DEBUG、SO_DONTROUTE、SO_KEEPALIVE、SO_LINGER、SO_OOBINLINE、SO_RCVBUF、SO_RCVLOWAT、SO_SNDBUF、SO_SNDLOWAT、TCP_MAXSEG、TCP_NODELAY
这对TCP是很重要的,因为accept一直要到TCP层完成三路握手后才会给服务器返回已连接套接字。如果想在三路握手完成时确保这些套接字选项中的某一个是给已连接套接字设置的,那么我们必须先给监听套接字设置该选项。
SO_BROADCAST 广播消息的能力 UDP
SO_DEBUG 内核将为TCP在该套接字发送和接收的所有分组保留详细跟踪信息 TCP
SO_DONTROUTE 规定外出的分组将绕过底层协议的正常路由机制
SO_ERROR 获取错误状态
SO_LINGER 指定close函数对面向连接的协议如何操作
SO_DONTLINER 若为真,则SO_LINGER选项被禁止
SO_KEEPALIVE 发送保持存活探测分节(心搏机制)
SO_OOBINLINE 当本选项开启时,带外数据将被留在正常的输入队列中(即在线留存)。这种情况下接受函数的MSG_OOB标志不能用来读带外数据。
SO_RCVBUF、SO_SNDBUF 修改发送缓冲区和接受缓冲区的大小
当设置TCP套接字接受缓冲区的大小时,函数调用的顺序很重要。这是因为TCP的窗口规模选项(2.6)是在建立连接时用SYN分节与对端互换得到的。对于客户,这意味着SO_RCVBUF选项必须在调用connect之前设置;对于服务器,这意味着该选项必须在调用listen之前给监听套接字设置。给已连接套接字设置该选项对于可能存在的窗口规模选项没有任何影响,因为accept知道TCP的三路握手完成才会创建并返回已连接套接字。(套接字缓冲区的大小总是由新创建的已连接套接字从监听套接字继承而来)
TCP套接字缓冲区的大小至少应该是相应连接的MSS值的四倍。
SO_RCVLOWAT、SO_SNDLOWAT 设置接收低水位标记和发送低水位标记
SO_RCVTIMEO、SO_SNDTIMEO 设置套接字接收和发送的超时值
SO_REUSEADDR
1.允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将该端口用作它们的本地端口的连接仍存在。
2.允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。
3.允许单个进程捆绑同一端口到多个套接字上,只要每次捆绑指定不同的本地IP地址即可。
4.允许完全重复的捆绑:当一个IP地址和端口已绑定在某个套接字上时,如果传输协议支持,同样的IP地址和端口还可以捆绑到另一个套接字上。一般来说本特性仅支持UDP套接字。
SO_REUSEPORT
1.本选项允许完全重复的捆绑,不过只有在想要捆绑同一IP地址和端口的每个套接字都指定了本套接字选项才行;
2.如果被捆绑的IP地址是一个多播地址,那么SO_REUSEADDR和SO_REUSEPORT被认为是等效的。
建议:
1.在所有TCP服务器程序中,在调用bind之前设置SO_REUSEADDR套接字选项;
2.当编写一个可在同一时刻在同一主机上运行多次的多播应用程序时,设置SO_REUSEADDR套接字选项,并将所参加多播组的地址作为本地IP地址捆绑。
SO_TYPE 返回套接字的类型
SO_USELOOPBACK 仅用于路由域(AF_ROUTE)的套接字。对于这些套接字,它的默认设置为打开(这是唯一一个默认值为打开而不是关闭的SO_二元套接字选项)。本选项开启时,相应套接字将接收在其上发送的任何数据报的一个副本。
IPPROTO_IP
IP_HDRINCL 如果本选项是给一个原始IP套接字设置的,那么我们必须为所有在该原始套接字上发送的数据报构造自己的IP首部。
下列情况例外:
IP总是计算并存储IP首部校验和
如果我们将IP标识字段置为0,内核将设置该字段。
如果源IP地址是INADDR_ANY,IP将把它设置为外出接口的主IP地址。
如何设置IP选项取决于实现。有些实现取出我们预先使用IP_OPTIONS套接字选项设置的任何IP选项,把它们添加到我们构造的首部中,而其他实现则要求我们亲自在首部指定任何期望的IP选项。
IP首部中有些字段必须以主机字节序填写,有些字段必须以网络字节序填写,具体取决于实现。这使得利用本套接字选项编排原始分组的代码不像期待的那样便于移植。
IP_OPTIONS 允许我们在IPv4首部中设置IP选项(27.3)
IP_RECVDSTADDR 导致所收到UDP数据报的目的IP地址由recvmsg函数作为辅助数据返回(22.2)
IP_RECVIF 导致所收到UDP数据报的接收接口索引由recvmsg函数作为辅助数据返回(22.2)
IP_TOS 允许我们为TCP、UDP或SCTP套接字设置IP首部中的服务类型字段(DSCP/ECN)
应用进程通常应该把ECN字段的设置留给内核,也就是把IP_TOS设置的值中的低两位指定为0。
IP_TTL设置或获取系统用在从某个给定套接字发送的单播分组上的默认TTL值(多播TTL值使用IP_MULTICAST_TTL套接字选项设置,21.6)
跟TOS字段一样,调用getsockopt返回的是系统将用于外出数据报的字段的默认值,我们没有办法从接收到的IP数据报中取得该值(图28-19)
IPPROTO_ICMPV6
ICMP6_FILTER 本选项允许我们获取或设置一个icmp6_filter结构,该结构指出256个可能的ICMPv6消息类型中哪些将经由某个原始套接字传递给所在进程(28.4)
IPPROTO_IPV6
IPV6_CHECKSUM 本选项指定用户数据中校验和所处位置的字节偏移
如果该值为非负,那么内核将:
给所有外出分组计算并存储校验和;
验证外来分组的校验和,丢弃所有校验和无效的分组。
本选项影响除ICMPv6原始套接字以外的所有IPv6原始套接字。内核总是给ICMPv6原始套接字计算并存储校验和。如果指定本选项的值为-1,那么内核不会在相应的原始套接字上计算并存储外出分组的校验和,也不会验证外来分组的校验和。
IPv6_DONTFRAG 开启本选项将禁止为UDP套接字或原始套接字自动插入分片首部,外出分组中大小超过发送接口MTU的那些分组将被丢弃。
应用进程应该开启IPV6_RECVPATHMTU选项以获悉路径MTU的变动
IPV6_NEXTHOP 将外出数据报的下一跳地址指定为一个套接字地址结构(22.8)
IPV6_PATHMTU 不能设置,只能获取。获取本选项时,返回值为由路径MTU发现功能确定的当前MTU(22.9)
IPV6_RECVDSTOPTS 开启本选项表明,任何接收到的IPv6目的地选项都将由recvmsg作为辅助数据返回(27.5)
IPV6_RECVHOPLIMIT 开启本选项表明,任何接收到的跳限字段都将由recvmsg作为辅助数据返回(22.8)
IPV6_RECVHOPOPTS 开启本选项表明,任何接收到的IPv6步跳选项都将由recvmsg作为辅助数据返回(27.5)
IPV6_RECVPATHMTU 开启本选项表明,某条路径的路径MTU在发生变化时将由recvmsg作为辅助数据返回(不伴随任何数据,22.9)
IPV6_RECVPKTINFO 开启本选项表明,接收到的IPv6数据报的“目的IPv6地址”和“到达接口索引”将由recvmsg作为辅助数据返回(22.8)
IPV6_RECVRTHDR 开启本选项表明,接收到的IPv6由首部将由recvmsg作为辅助数据返回(27.6)
IPV6_RECVTCLASS 开启本选项表明,接收到的流通类别(DSCP/ECN)将由recvmsg作为辅助数据返回(22.8)
IPV6_UNICAST_HOPS 类似于IP_TTL,设置本选项会给在相应套接字上发送的外出数据报指定默认跳限,获取本选项会返回内核用于相应套接字的跳限值。
IPV6_USE_MIN_MTU 把本选项设置为1表明,路径MTU发现功能不必执行,为避免分片,分组就是用IPv6的最小MTU发送。把本选项设置为0表明,路径MTU发现功能对于所有目的地都得执行。把本选项设置为-1表明,路径MTU发现功能仅对单播目的地执行,对于多播目的地就使用最小MTU。默认值为-1。
IPV6_V6ONLY 在一个AF_INET6套接字上开启本选项将限制它只执行IPv6通信。
IPV6_XXX 大多数用于修改协议首部的IPv6选项假设:就UDP套接字而言,信息由recvmsg和sendmsg作为辅助数据在内核和应用进程之间传递;就TCP套接字而言,同样的信息改用getsockopt和setsockopt获取和设置。套接字选项和辅助数据的类型一致,并且访问套接字选项的缓冲区所含的信息和辅助数据中存放的信息也一致(27.7)
IPPROTO_TCP
TCP_MAXSEG 允许我们获取或设置TCP连接的最大分节大小(MSS)
TCP_NODELAY 开启本选项将禁止TCP的Nagle算法。Nagle算法的目的在于防止一个连接在任何时刻有多个小分组带确认。Nagle算法常常与ACK延滞算法(delayed ACK algorithm)联合使用。
处理小分组的方法:
1.使用writev而不是多次调用write
2.先将数据复制到单个缓冲区,再对该缓冲区调用一次write
3.设置TCP_NODELAY套接字选项,继续调用write两次。这是最不可取的办法,而且有损于网络,通常不应该考虑。
IPPROTO_SCTP
sctp_opt_info 在getsockopt支持双向数据传递的系统上,sctp_opt_info只是getsockopt的一个简单外包。
SCTP_ADAPTION_LAYER 允许调用者获取或设置由本端提供给对端的适配层指示
获取本选项的值时,调用者得到的是本地套接字将提供给所有未来对端的值。要获取对端的适配层指示,应用进程必须预定适配层事件。
SCTP_ASSOCINFO
获取关于某个现有关联的信息
改变某个已有关联的参数
为未来的关联设置默认信息
SCTP_AUTOCLOSE 允许我们获取或设置一个SCTP端点的自动关闭时间,自动关闭时间是一个SCTP关联在空闲时保持打开的秒数
SCTP协议栈把空闲定义为一个关联的两个端点都没有在发送或接收用户数据的状态
SCTP_DEFAULT_SEND_PARAM 希望发送大量消息且所有消息具有相同发送参数的应用进程可以使用本选项设置默认参数,从而避免使用辅助数据或执行sctp_sendmsg调用
SCTP有许多可选的发送参数,它们通常作为辅助数据传递,或者由sctp_sendmsg函数使用
注意,所有默认设置只影响没有指定sctp_sndrcvinfo结构的消息发送。指定了该结构的消息发送将覆写默认设置。除了进行默认设置,通过使用sctp_opt_info函数,本选项也可用于获取当前的默认设置。
SCTP_DISABLE_FRAGMENTS SCTP通常把太大而不适合单个SCTP分组中的用户消息分割成多个DATA块,开启本选项将在发送端禁止这种行为。
SCTP_EVENTS 本套接字选项允许调用者获取、开启或禁止各种SCTP通知 sctp_event_subscribe
SCTP_GET_PEER_ADDR_INFO 本选项仅用于获取某个给定对端地址的相关信息,包括拥塞窗口、平滑化后的RTT和MTU等。
把一个IP地址结构转换成一个可用于其他调用的关联标识;
由应用进程跟踪一个多宿对端主机每个地址的性能,并把对应关联的主目的地址更新为其中性能最佳的一个。
这些值也同样有利于日志记录和程序调试。
SCTP_I_WANT_MAPPED_V4_ADDR 用于为AF_INET6类型的套接字开启或禁止IPv4映射地址,默认为开启。
SCTP_INITMSG 用于获取或设置某个SCTP套接字在发送INIT消息时所用的默认初始参数。
注意,当设置这些字段时,SCTP将忽略其中的任何0值
SCTP_MAXBURST 允许应用进程获取或设置用于分组发送的最大猝发大小。当SCTP向对端发送数据时,一次不能发送多于这个数目的分组,以免网络被分组淹没。
具体的SCTP实现有两种方法应用这个限制:
1.把拥塞窗口缩减为当前飞行大小加上最大猝发大小与路径MTU的乘积
2.把该值作为一个独立的微观控制量,在任意一个发送机会最多只发送这个数目的分组
SCTP_MAXSEG 允许应用进程获取或设置用于SCTP分片的最大片段大小
最大片段大小是一个端点范围的设置,在一到多式接口中,它可能影响不止一个关联
SCTP_NODELAY 开启本选项将禁止SCTP的Nagle算法
SCTP的Nagle算法与TCP的Nagle算法工作原理相同,区别在于前者对付多个DATA块,后者对付单个流上的字节
SCTP_PEER_ADDR_PARAMS 允许应用进程获取或设置关于某个关联的对端地址的各种参数 sctp_paddrparams
SCTP_PRIMARY_ADDR 用于获取或设置本地端点所用的主目的地址。主目的地址是本端发送给对端的所有消息的默认目的地址。 sctp_setpri(ssp_assoc_id)
注意,在只有一个本地地址与之关联的一到一式套接字上获取本选项的值跟直接调用getsockname是一样的。
SCTP_RTOINFO 用于获取或设置各种RTO信息,它们既可以是关于某个给定关联的设置,也可以是用于本地端点的默认设置。 sctp_rtoinfo
RTO 超时重传机制
SCTP_SET_PEER_PRIMARY_ADDR 设置本套接字选项导致发送一个消息:请求对端把所指定的本地地址作为它的主目的地址 sctp_setpeerprim
调用者必须在该结构中填写关联标识和一个请求对端标为其主目的地址的本地地址。这个本地地址必须已经绑定在本地端点。
本特性是可选的,只有两端均支持才能运作。另外注意,本套接字选项只能设置,不能获取。
SCTP_STATUS 用于获取某个SCTP关联的状态 sctp_status(sstat_assoc_id)
fcntl函数提供了与网络编程相关的如下特性:
非阻塞式I/O。通过使用F_SETFL命令设置O_NONBLOCK文件状态标志,我们可以把一个套接字设置为非阻塞型(16)。
信号驱动式I/O。通过F_SETFL命令设置O_ASYNC文件状态标志,我们可以把一个套接字设置成一旦其状态发生变化,内核就产生一个SIGIO信号(25)。
F_SETOWN命令允许我们指定用于接受SIGIO和SIGURG信号的套接字属主(进程ID或进程组ID),其中SIGIO信号是套接字被设置为信号驱动式I/O型后产生的(25),SIGURG信号是在新的带外数据到达套接字时产生的(24).F_GETOWN命令返回套接字的当前属主。
设置某个文件状态标志的唯一正确的方法是:先取得当前标志,与新标志逻辑或后再设置标志。
int flags;
if((flags = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("F_GETFL error");
flags |= O_NONBLOCK;
if(fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
flags &= ~O_NONBLOCK;
if(fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
信号SIGIO和SIGURG与其他信号的不同之处在于,这两个信号仅在已使用F_SETOWN命令给相关套接字指派了属主后才会产生。
指定接收信号的套接字属主为一个进程或一个进程组的差别在于:前者仅导致单个进程接收信号,而后者则导致整个进程组中的所有进程(也许不止一个进程)接收信号。
使用socket函数新创建的套接字并没有属主。然而如果一个新的套接字是从一个监听套接字创建来的,那么套接字属主将由已连接套接字从监听套接字继承而来。