菜鸟笔记
提升您的技术认知

《unix网络编程》套接字选项

阅读 : 301

getsockopt和setsockopt函数

#include  
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen); 
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
//若成功发回0,出错返回-1

参数:  

sock:指向一个套接字描述符,将要被设置或者获取选项的套接字。

level:指定系统中解释选项的代码或为通用套接字代码,或为某个特定于协议的代码

optname:需要访问的套接字选项名。

optval:指针,对于getsockopt(),指向返回选项值的缓冲,该函数把已经获得的选项当前值存放到*optval中。

                      对于setsockopt(),指向包含新选项值的缓冲,该函数从*optval中取的选项设置的新值。

optlen:对于getsockopt(),值-结果参数:作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。

            对于setsockopt(),值参数,现选项的长度。

给出部分套接字选项,用到哪个再继续添加:

通用套接字选项SO_SOCKET

1 SO_BROADCAST

开启或禁止进程发送广播消息的能力。

只有数据报套接字支持广播,并且必须是在支持广播消息的网络上(如以太网、令牌环网),不能在点对点链路上进行广播,也不能在基于连接的传输协议(TCP)之上进行广播。

2 SO_DEBUG

打开或关闭调试信息。

开启该选项,内核将为TCP在该套接字发送和接收的所有分组保留详细的跟踪信息。这些信息保留在内核的某个环形缓冲区,并可使用trpt程序检查。

3 SO_DONTROUTE

打开或关闭路由查找功能。

该选项规定外出的分组将绕过底层协议的正常路由机制。

路由守护进程(routed和gated)经常使用该选项绕过路由表(路由表不正确),以强制将分组从特定接口送出。

4 SO_ERROR

进程通过该选项获取so_error的值。由getsockopt返回的整数值就是该套接字的待处理错误。so_error由内核复位为0.

这是第一个只可以获取但不能设置的套接字选项

5 SO_KEEPALIVE

自动终止半开连接。

本选项功能是检测对端主机是否崩溃或者变得不可达。该选项无法区分这两种情况。一般由服务器使用该选项,客户也可用。

        设置了该套接字,如果两个小时(两小时这个参数可改,但是这是内核维护的时间,是全局的,会影响所有打开该选项的套接字)内在该套接字上的任何一方没有数据交换,TCP会自动给对端发送一个保持存活探测字节(keep-alive probe),这是对端必须响应的TCP分节。

   服务器使用该选项是因为它们花大部分时间阻塞在等待穿越TCP连接的输入上,也就是等待客户的请求。然而,如果客户主机连接掉线、电源掉电或系统崩溃,服务器将永远不知道,会继续等待永远不会到达的输入,称此情况为半开连接。该选项将检测出这些半开连接并终止它们。

        有些服务器(特别是FTP服务器)提供一个分钟级别的应用层超时,这个超时与本套接字无关。这通常是清理通向不可达客户的半开连接的好办法。

6 SO_LINGER

针对面向连接的协议。

       默认情况下,close立即返回,但是如果有数据残留在套接字发送缓冲区中,系统将试着把这些数据发送给对端;该套接字可以改变这个默认设置。使得我们能够更好的控制close函数返回的时机,而且允许我们强制发送RST而不是TCP的四个分组连接终止序列。必须小心发送RST,因为这么做会回避TCP的TIME_WAIT状态存在这样的可能:在2MSL秒内创建该链接的另一个化身,导致来自刚被终止的连接上的旧的重复分节被不正确地递送到新的化身)。

7 SO_RCVBUF和SO_SNDBUF

改变缓冲区大小。

        每个套接字都有一个发送缓冲区和一个接收缓冲区。
        接收缓冲区被TCP,UDP和SCTCP用来保存接收到的数据,直到由应用进程读取。对于TCP来说,套接字接收缓冲区可用空间的大小限制了TCP通告对端的窗口大小。TCP套接字接收缓冲区不可以溢出,因为不允许对端发出超过本端所通告窗口大小的数据。这就是TCP的流量控制,如果对端无视窗口大小而发出了超过窗口大小的数据,本端TCP将丢弃它们。然而对于UDP来说,当接收到的数据报装不进套接字接收缓冲区时,该数据报就被丢弃。回顾一下,UDP是没有流量控制的:较快的发送端可以很容易的淹没较慢的接收端,导致接收端的UDP丢弃数据报。
       这两个套接字选项允许我们改变着两个缓冲区的默认大小。对于不同的实现,默认值得大小可以有很大的差别。如果主机支持NFS,那么UDP发送缓冲区的大小经常默认为9000字节左右的一个值,而UDP接收缓冲区的大小则经常默认为40000字节左右的一个值。
       当设置TCP套接字接收缓冲区的大小时,函数调用的顺序很重要。这是因为TCP的出口规模选项时在建立连接时用SYN分节与对端互换得到的。对于客户,这意味着SO_RCVBUF选项必须在调用connect之前设置;对于服务器这意味着该选项必须在调用listen之前给监听套接字设置。给已连接套接字设置该选项对于可能存在的出口规模选项没有任何影响,因为accept直到TCP的三路握手玩抽才会创建并返回已连接套接字。这就是必须给监听套接字设置本选项的原因。

8 SO_REUSEADDR和SO_REUSEPORT

 SO_REUSEADDR套接字选项能起到以下4个不同的功用。
(1)SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知的端口,即使以前建立的将该端口用作他们的本地端口的连接仍存在。这个条件通常是这样碰到的:
        (a)启动一个监听服务器;
        (b)连接请求到达,派生一个子进程来处理这个客户;
        (c)监听服务器终止,但子进程继续为现有连接上的客户提供服务;
        (d)重启监听服务器。     
        默认情况下,当监听服务器在步骤d通过调用socket,bind和listen重新启动时,由于试图捆绑一个现有连接(即正由早先派生的那个子进程处理着的连接)上的端口,从而bind调用会失败。但是如果该服务器在socket和bind两个调用之间设置了SO_REUSEADDR套接字选项,那么将成功。所有TCP服务器都应该(在调用bind之前)指定本套接字选项,以允许服务器在这种情况下被重新启动。SO_REUSEADDR的使用参见文章epoll函数中的服务器端程序。

(2)SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们绝对不可能启动捆绑相同IP地址和相同端口号的多个服务器:这是完全重复的捆绑,即使我们给第二个服务器设置了SO_REUSEADDR套接字也不管用。

(3)SO_REUSEADDR 允许单个进程捆绑同一端口到多个套接字上,只要每次捆绑指定不同的本地IP地址即可。

(4)SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口号已绑定到某个套接字上时,如果传输协议支持,同样的IP地址和端口还可以捆绑到另一个套接字上。一般来说本特性仅支持UDP套接字。