- 这些选项是协议无关的(也就是说,它们由内核中的协 议无关代码处理,而不是由诸如IPv4之类特殊的协议模块处理),不过其中有些选项只能应用到某些特定类型的套接字中。举例来说,尽管我们称SO_BROADCAST套接字选项是“通用”的,它 却只能应用于数据报套接字
一、SO_BROADCAST
- 本选项开启或禁止进程发送广播消息的能力。只有数据报套接字支持广播,并且还必须是在支持广播消息的网络上(例如以太网、令牌环网等)。我们不可能在点对点链路上进行广播, 也不可能在基于连接的传输协议(例如TCP和SCTP)之上进行广播
- 由于应用进程在发送广播数据报之前必须设置本套接字选项,因此它能够有效地防止一个 进程在其应用程序根本没有设计成可广播时就发送广播数据报。举例来说,一个UDP应用程序 可能以命令行参数的形式取得目的IP地址,不过它并不期望用户键入一个广播地址。处理方法 并非让应用进程来确定一个给定地址是否为广播地址,而是在内核中进行测试:如果该目的地 址是一个广播地址且本套接字选项没有设置,那么返回EACCES错误(TCPv2第233页)。
二、SO_DEBUG
- 本选项仅由TCP支持。当给一个TCP套接字开启本选项时,内核将为TCP在该套接字发送和接收的所有分组保留详细跟踪信息。这些信息保存在内核的某个环形缓冲区中,并可使用trpt 程序进行检查
- TCPv2第916~920页提供了更为详细的信息和使用了本选项的一个例子
三、SO_DONTROUTE
- 本选项规定外出的分组将绕过底层协议的正常路由机制。举例来说,在IPv4情况下外出分组将被定向到适当的本地接口,也就是由其目的地址的网络和子网部分确定的本地接口。如果 这样的本地接口无法由目的地址确定(譬如说目的地主机不在一个点对点链路的另一端,也不 在一个共享的网络上),那么返回ENETUNREACH错误
- 给函数send、sendto或sendmsg使用MSG_DONTROUTE标志也能在个别的数据报上取得与本选项相同的效果
- 路由守护进程(routed和gated)经常使用本选项来绕过路由表(路由表不正确的情况下), 以强制将分组从特定接口送出
四、SO_ERROR
- 当一个套接字上发生错误时,源自Berkeley的内核中的协议模块将该套接字的名为so_error的变量设为标准的Unix Exxx值中的一个,我们称它为该套接字的待处理错误(pending error)
- 内核能够以下面两种方式之一立即通知进程这个错误:
- ①如果进程阻塞在对该套接字的select调用上,那么无论是检查可读条件还是可 写条件,select均返回并设置其中一个或所有两个条件
- ②如果进程使用信号驱动式I/O模型(第25章),那就给进程或进程组产生一个SIGIO信号。 进程然后可以通过访问SO_ERROR套接字选项获取so_error的值。由getsockopt返回的整 数值就是该套接字的待处理错误。so_error随后由内核复位为0(TCPv2第547页)
- 当进程调用read且没有数据返回时,如果so_error为非0值,那么read返回-1且errno被 置为so_error的值(TCPv2第516页)。so_error随后被复位为0。如果该套接字上有数据在排 队等待读取,那么read返回那些数据而不是返回错误条件。如果在进程调用write时so_error 为非0值,那么write返回-1且errno被设为so_error的值(TCPv2第495页)。so_error随后被 复位为0
- 这是我们遇到的第一个可以获取但不能设置的套接字选项
- 演示案例:
五、SO_KEEPALIVE
- 待续
六、SO_LINGER
-
待续
七、SO_OOBINLINE
-
当本选项开启时,带外数据将被留在正常的输入队列中(即在线留存)。这种情况下接收函 数的MSG_OOB标志不能用来读带外数据。我们将在后面文章中详细讨论带外数据
八、SO_RCVBUF 和 SO_SNDBUF
九、SO_RCVLOWAT 和 SO_SNDLOWAT
- 每个套接字还有一个接收低水位标记和一个发送低水位标记。它们由select函数使用。这两个套接字选项允许我们修改这两个低水位标记
- 接收低水位标记是让select返回“可读”时套接字接收缓冲区中所需的数据量。对于TCP、 UDP和SCTP套接字,其默认值为1
- 发送低水位标记是让select返回“可写”时套接字发送缓冲区中所需的可用空间。对于TCP套接字,其默认值通常为2048
- 如select文章中所述,UDP也使用发送低水位标记,然而由于UDP套接字的发送缓冲区中可用空间的字节数从不改变(因为UDP并 不为由应用进程传递给它的数据报保留副本),只要一个UDP套接字的发送缓冲区大小大于该套 接字的低水位标记,该UDP套接字就总是可写。回顾UDP的缓冲区,我们记得UDP并没有发送缓冲区, 而只有发送缓冲区大小这个属性
十、SO_RCVTIMEO 和 SO_SNDTIMEO
- 这两个选项允许我们给套接字的接收和发送设置一个超时值。注意,访问它们的 getsockopt和setsockopt函数的参数是指向timeval结构的指针,与select所用参数相同。这可让我们用秒数和微秒数来规定超时。我们通过设置其值为0s和0µs来禁止超时。默认 情况下这两个超时都是禁止的
- 接收超时影响5个输入函数:read、readv、recv、recvfrom和recvmsg。发送超时影响5个输出函数:write、writev、send、sendto和sendmsg。我们将在后面文章详细讨论套接字超时
十一、SO_REUSEADDR 和 SO_REUSEPORT
演示案例
- 设置SO_REUSERADDR选项来强制使用被处于TIME_WAIT状态的连接占用的socket地址,经过设置之后,即使sock处于TIME_WAIT状态,与之绑定的socket地址也可以立即被重用
- 我们也可以通过修改内核参数/proc/sys/net/ipv4/cp_tw_recycle来快速回收被关闭的socket,从而使得TCP连接根本就不进入IME_WAIT状态,进而允许应用程序立即重用本地的socket地址
int sock=socket(AF_INET,SOCK_STREAM,0); assert(sock); int reuse=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)); struct sockaddr_in address; ...... ...... int ret=bind(sock,(sruct sockaddr*)&address,sizeof(address));
十二、SO_TYPE
- 本选项返回套接字的类型
- 返回的整数值是一个诸如SOCK_STREAM或SOCK_DGRAM之类的值。本选项通常由启动时继承了套接字的进程使用。
十三、SO_USELOOPBACK
- 本选项仅用于路由域(AF_ROUTE)的套接字。对于这些套接字,它的默认设置为打开(这 是唯一一个默认值为打开而不是关闭的SO_xxx二元套接字选项)。当本选项开启时,相应套接字 将接收在其上发送的任何数据报的一个副本
- 禁止这些环回副本的另一个方法是调用shutdown,并设置它的第二个参数为SHUT_RD