
//-----------------------------------1.getsockopt和setsockopt--------------------------------------
#include <sys/socket.h>
int getsockopt(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);
其中sockfd需要是开启的套接字描述符,level(级别)指定平台中解释选项的代码或为通用套接字代码,或为某个特定于协议的代码(例如ipv4,ipv6,tcp或sctp)。
optval是指向某个函数(*optval)的指针,setsockopt从*optval中获得选项待修改的新值,getsockopt则把即将拿到的选项当前值保存放到optval中,*optval的大小由最后一个参数指定,它针对setsockopt是一个值参数,对于getsockopt是一个值结果参数。
套接字选项粗粗地分为两大基本种类,一是实行或允许某个特点的二元选项(称为标志选项),二是获得并返回我们可以修改或检测的特定值的选项(称为值选项)。
当为标志选项时,*optval是一个整数,*optval中返回的值为0表示相应选项被引入,不为0表示相应选项被引入,类似地,setsockopt函数必须一个不为0的*optval值来引入选项,一个为0的*optval值来允许选项。
当为值选项时,那么该选项是用于在用户进程与平台之间释放所指定数据类别的值。
//------------------------------------2.套接TCP状态-------------------------------------------
针对套接字的状况,什么时候设置或获得选项有时序上的考量,,例如,下面的套接字选项是由已连接套接字从字继承来的,SO_DEBUG,SO_DONTROUT,SO_KEEPALIVE,SO_LINGER,SO_OOBINLINE,SO_RCVBUF,SO_RCVLOWAT,SO_SNDBUF,SO_SNDLOWAT,TCP_MAXSEG和TCP_NODELAY.这对TCP是很重要的,因为accpet一直要到TCP层完成三路握手后能够给服务器返回已连接套接字。如果我们想在三路握手完成时确保这种套接字选项中的某一个是给已连接套接字设置的,那么我们应该先给套接字设置该选项。
//-----------------------------------3.一些通用套接字选项-------------------------------------
因为套接字选项有很多,不也许每个都记得下,所以没法选择一些常见且重要的来记住,其他的就当字典似的还要时来查。
SO_DONTROUTE套接字选项:

本选项要求外出的分组将跳过底层协议的正常路由模式,举例子来说,在ipv4情况下外出分组将被定向到适当的本地接口,也就是由其目的地址的网络和子网部分确认的本地接口。如果这种的本地接口能够由目的地址确认(譬如说目的地主机不在一个点对点链路的另一端,也不在一个共享的网络上),那么返回ENETUNREACH错误。路由守护进程(routed和gated)经常使用本选项来跳过路由表(路由表不正确的状况下),以强行将分组从特定接口送出。
SO_KEEPALIVE套接字选项:
给一个TCP套接字设置保持存活选项后,如果2小时内在该套接字的任一方向上都没有数据交换,TCP就手动给对端发送一个保持存活探测分节,这是一个对端需要响应的TCP分节,它会导致如下三种状况之一:
1).对端以希望的ACK响应,应用进程得不到通知,因为一切正常,在又经过仍无动静的2小时后,TCP将发出另外也给探测分节。
2).对端以RST响应,它告知本端TCP:对端已崩溃且尚未重新启动,该套接字的待处理错误被置ECONNRESET,套接字本身则被关闭。
3).对端对维持存活探测分节没有任何响应,源自Berkeley的TCP将另外发送8个探测分节,两两相隔75秒,试图得到一个响应,TCP在发出第一个探测分节后11分15秒内若没有得到任何响应则舍弃。该套接字的待处理错误就被置为ETIMEOUT,套接字本身则被关闭。然而一旦该套接字收到一个ICMP错误成为某个探测分节的响应,那就返回响应的出错,套接字本身也呗关闭,这种情形下待处理的错误即是EHOSTUNREACH,说明对端主机可能并没有崩溃,只是不可达,原因也许是网络出现故障,或者是对端主机尚未崩溃,而最终一跳的路由器也终于测试到它的崩溃。
下图对一个TCP连接的另一端发生这种事故时我们可以采取的各类检查方法做了汇总:
SO_LINGER套接字选项:
本选项指定close函数对面向连接的协议(例如TCP和SCTP,但不是UDP)如何操作,默认操作是close立即返回,但是一旦有数据残留在套接字发送缓冲区中,系统将试着把这种数据发送给对端。
SO_LINGER套接字选项并且我们可以改变这个默认设定,本选项规定在用户进程与内核间释放如下结构,它在头文件<sys/socket.h>中定义:
struct linger {
int l_onoff;
int l_linger;

};
对setsockopt的调用将按照其中2个结构成员的值产生以下3种情形之一:
1).如果l_onoff为0,那么关闭本选项,l_linger的值也被忽视,先前讨论的TCP默认设定生效,级close立即返回。
2).如果l_onoff为非0值且l_linger为0,那么当close某个连接时TCP将停止该连接。这就是说TCP将丢弃保留在套接字发送缓冲区中的任何数据,并发送一个RST给对端,而没有通常的四分组连接中止序列,这么一来避免了TCP的TIME_WAIT状态,然而存在以上可能性:即在2MSL秒内建立该链接的另一个化身,导致来自刚被终止的连接上的旧的重复分节被不正确地递送到新的化身上。
3).如果l_onoff为非0值且l_linger也为非0值,那么当套接字关闭时,内核将拖延一段时间,这就是说如果在套接字发送缓冲区中仍残留有数据,那么进程将被投入睡眠,直到所有数据都已发送完且均被他人确认或延滞时间到。如果套接字被修改为非阻塞型,那么它将不期待close完成,即时延滞时间为非0也是这么。当使用SO_LINGER选项的这个特点时,应用进程检测close的返回值是比较重要的,因为一旦在数据发送完并被确定前延滞时间到的话,close将返回EWOULDBLOCK错误,且套接字发送缓冲区中的任何残留数据都被抛弃。
下图汇总了shutdown的两种可能调用和对close的三种可能调用,以及他们对TCP套接字的影响:
SO_RCVBUF和SO_SNDBUF选项:
每个套接字都有一个发送缓冲区和一个接收缓冲区,对于TCP来说,套接字接收缓冲区中只用空间的大小限定了TCP通告对端的窗口大小。TCP套接字接收缓冲区不也许溢出,因为不允许对端发出超过本端所公告窗口大小的数据,这就是TCP的流量控制,如果对端无视窗口大小而发出了超出本端所公告窗口大小的数据,本端TCP将抛弃他们。然而针对UDP来说,当接收到的数据报装不进套接字接收缓冲区时,该数据报就被丢弃。
套接字缓冲区的大小总是由新建立的已连结套接字从套接字继承而来,意味着,对于用户,SO_RECVBUF选项需要在读取connect之前设置;对于服务器,必须在读取listen之前给套接字设置。
TCP套接字缓冲区的大小必须起码是相应连接的MSS值的4倍,这一点的根据是TCP快速修复算法的工作模式,TCP发送端使用3个重复的确定来检查某个分节是否损坏,发现某个分节丢失后,接收端将给新收到的每位分节发送一个重复的确定,如果窗口大小不足以存放4个这样的分节,那就不也许连发三个重复的确定,从而能够唤醒快速修复算法。
为防止潜在缓冲区空间的浪费,TCP套接字缓冲区大小还必须是相应连接的MSS值的偶数倍,有些实现题应用进程处理这个细节问题,在联结建立以后,向上舍入套接字缓冲区大小,使用默认的4.4BSD大小8192举例来说,假设以太网的MSS值为1460,在联接搭建时收发两个套接字接收缓冲区的大小将被向上舍入成8760(6*1460),这个规定只是需要,只不过套接字缓冲区中的MSS整数倍大小以外的空间不会被使用。
SO_RCVLOWAT和SO_SNDLOWAT选项:
每个套接字还有一个接收低水位标记和一个发送低水位标记,它们由select函数使用,这两个套接字选项允许我们设置这2个低水位标记。

接收低水位标记是让select返回“可读”时套接字缓冲区中所需的数据量,对于TCP和UDP和SCTP套接字来说,器默认值为1。发送低水位标记是让select返回“可写”时套接字发送缓冲区中所必须的空间,对于TCP套接字,其默认值通常为2048。
SO_RCVTIMEO和SO_SNDTIMEO选项:
这2个选项允许我们给套接字的接收和发送修改一个超时值,注意访问他们的getsockopt和setsockopt函数的参数是指向timeval结构的指针,与select所用参数相近,与select所用参数同样。我们可借助修改其0s和0us来允许超时,默认都是静禁止的。
SO_REUSEADDR和SO_REUSEPORT选项:
1).SO_REUSEADDR允许开启一个服务器并捆绑其众所周知端口,即使当时制定的将该端口用作它们的本地端口的连接并且存在
a)启动一个服务器
b)连接请求到达,派生一个子进程来处理这个客户
c)服务器终止,但是子进程继续为现有连接上的用户提供服务
d)重启服务器
如果服务器在socket 和 bind两个调用之间设定了SO_REUSEADDR套接字选项,那么bind将失败。
2).SO_REUSEADDR允许在同一个端口上开启同一服务器的多个例子,只要每位实例捆绑一个不同的IP地址就能。
//------------------------------------4.TCP的两个套接字选项----------------------------------------
TCP_MAXSEG套接字选项:
本选项禁止我们获得或修改TCP连接的最大分节大小(MSS),返回值是我们的TCP可以发送给对端的最大数据量,它一般是由对端使用SYN分节通告的MSS,除非我们的TCP选择使用一个比对端通告的MSS小些的值。如果该值在相应套接字的联结建立之前取得,那么返回值是从未对端收到MSS选项的状况下所用的默认值,还得切记的是,如果用上譬如说时间戳选项的话,那么实际用于联结中的最大分节大小也许小于本地套接字选项的返回值,因为时间戳选项在每个分节中要占用12字节的TCP选项容量。

如果TCP支持模式MTU发现功能,那么它将发送的每个分节的最大数据量还或许在连接存活期内改变,如果到对端的模式出现变动,该值就会有所调准。
TCP_NODELAY套接字选项:
开启本选项将允许TCP的Nagle算法,默认状况下该算法是开启的。
Nagle算法的目的在于增加广域网(wlan)上小分组的数量,该算法指出:如果某个给定连接上有待确认的数据(outstanding data),那么当时需要成为客户写操作之响应的在该连接上立刻发送相应小分组的行为就不会发生,直到现有数据被确定为止。这里小分组的定义就是小于MSS的任何分组,TCP总是尽可能地发送最大大小的分组,Nagle算法的目的在于避免一个连接在任何时刻有多个小分组待确定。
假设Nagle算法是允许的,我们将得到如下图的12个分组。
但是一旦Nagle算法是进入的(默认情形),将得到如下的8个分组。
(假设用户每250ms输入一个字符unp和apue阅读顺序,上图忽略了用户对服务器的ACK)第一个字符独自作为一个分组,然而下2个字符没有立即发送,因为该连接上有一个小分组待确定。在时刻600ms处收到对端对第一个分组的ACK后(该ACK由第一个字符的回显捎带),这2个字符才发送。在该分组在时刻1200ms处被确定之前,没有其他小分组被发送,Nagle始终维持一个连接在任何时刻有多个有多个分组待证实。(待确定数据是指未决数据,也就是已发送,但还在期待对端确定的数据)。
Nagle算法常常与此外一个TCP算法联合使用:ACK延滞算法,该算法进而TCP在接收到数据后不及时发送一个ACK,而是期待一小段时间(典型值为50~200ms),然后才发送一个ACK。TCP期待在这一小段时间内自身有数据发送回对端,被延滞的ACK就可以由很多数据捎带,从而省下一个TCP分节。这种情形对于Rlogin和Telnet客户来说通常可行,因为他们的服务器一般都回显客户发送来的每个字符unp和apue阅读顺序,这样对客户端字符的ACK完全可以在服务器对该数组回显中捎带返回。然而针对其服务器不在相反方向形成数据从而携带ACK的用户来说,ACK延滞算法存在弊端,客户会感觉到明显的提早,因为用户TCP要直到服务器的ACK延滞定时器超时才再次给服务器发送数据。这些用户必须一种禁止Nagle算法的方式,TCP_NODELY选项即可起到这个作用。
//----------------------------------------5.fcntl函数------------------------------------------
#include <fcntl.h>
int fcntl(int fd, int cmd, .../* int arg */);
fcntl函数提供了与网络编程相关的如下特性:
1).非阻塞式I/O:通过使用F_SETFL命令修改O_NONBLOCK文件状态标志,我们可以把一个套接字设置为非阻塞型。
2).信号驱动式I/O:通过使用F_SETFL命令修改O_ASYNC文件状态标志,我们可以把一个套接字设置成即使其状况出现差异,内核就形成一个SIGIO信号。
3).F_SETOWN命令禁止我们选定用于接收SIGIO和SIGURG信号的套接字属主(进程id或进程组id),其中SIGIO信号是套接字被设定为信号驱动式I/O型产生的,SIGURG信号是在新的带外数据到达套接字时候造成的,F_GETOWN命令返回套接字的当前属主。不得不提的是,信号SIGIO和信号SIGURG与其它信号的不同之处在于:这2个信号只是在已使用F_SETOWN命令的整数类型arg参数既可以是一个整数,指出接收信号的进程id,也可以是也给负整数,其绝对值指出接收信号的进程组id。F_GETOWN命令把套接字属主成为fcntl函数的返回值返回,它既可以是进程ID(一个正的返回值)也可以是进程组ID(一个除-1外的负值),指定接收信号的套接字属主为一个进程或一个进程组的差异在于:前者只是造成单个进程接收信号,而后者则造成整个进程组中的所有进程接收。使用socket函数新建立的套接字并没有属主,然而一旦一个套接字是从一个套接字创建来的,那么该套接字属主讲由已连接套接字从套接字继承而来。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-124074-1.html
看做事一种反社会行为呢
希望塑造好的作品和借助好的平台