获取和设置影响套接字的选项:
#include
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);
/* 均返回:若成功则为0,若出错则为-1 */
套接字选项分为两大基本类型:
一是启用或禁止某个特性的二元选项(称为标志选项)。
二是取得并返回我们可以设置或检查的特定值的选项(称为值选项)。
下面的套接字选项是由TCP已连接套接字从监听套接字继承来的:
SO_DEBUG、SO_DONTROUTE、SO_KEEPALIVE、SO_LINGER、SO_OOBINLINE、SO_RCVBUF、SO_RCVLOWAT、SO_SNDBUF、SO_SNDLOWAT、TCP_MAXSEG、TCP_NODELAY。
因为accept一直要到TCP层完成三路握手后才会给服务器返回已连接套接字。如果想在三路握手完成时确保这些套接字选项中的某一个是给已连接套接字设置的,那么我们必须先给监听套接字设置该选项。
SO_BROADCAST套接字选项
本选项开启或禁止发送广播消息的能力。只有数据报套接字支持广播。
SO_DEBUG套接字选项
本选项仅由TCP支持。开启时,内核将为TCP在该套接字发送和接收的所有分组保留详细跟踪信息。这些信息保存在内核的某个环形缓冲区中,并可使用trpt程序进行检查。
SO_DONTROUTE套接字选项
本选项规定外出的分组将绕过底层协议的正常路由机制。
SO_ERROR套接字选项
当一个套接字上发生错误时,源自Berkeley的内核中的协议模块将该套接字的明文so_error的变量设为标准的Unix_Exxx值中的一个,我们称它为套接字的待处理错误(pending error),内核能够以下面两种方式之一立即通知该错误:
a)如果进程阻塞在对该套接字的select调用上,那么无论是检查可读条件还是可写条件,select均返回并设置其中一个或所有两个条件。
b)如果进程使用信号驱动式I/O模型,那就给进程或进程组产生一个SIGIO信号。
SO_KEEPALIVE套接字选项
设置后,如果2小时内无数据交换,TCP就会自动发送一个保持存活探测分节(keep-alive probe)。结果如下:
1)对端以期望的ACK响应,则一切正常,应用程序得不到通知;
2)对端以RST响应,套接口的待处理错误被置为ECONNRESET,套接口本身则被关闭;
3)对端对探测分节无任何响应,经过重试都没有任何响应,套接口的待处理错误被置为ETIMEOUT,套接口本身被关闭;若接收到一个ICMP错误作为某个探测分节的响应,则返回相应错误。
SO_LINGER套接字选项
此选项指定函数close对面向连接的协议如何操作(如TCP)。缺省close操作是立即返回,如果有数据残留在套接口缓冲区中则系统将试着将这些数据发送给对方。
SO_LINGER选项用来改变此缺省设置。使用如下结构:
#include
struct linger {
int l_onoff; /* 0=off, nonzero=on */
int l_linger; /* linger time, POSIX specifies units as seconds */
};
有下列三种情况:
1)l_onoff为0,则该选项关闭,l_linger的值被忽略,等于缺省情况,close立即返回;
2)l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;
3)l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完成。
l_linger的单位依赖于实现,4.4BSD假设其单位是时钟滴答(百分之一秒),但Posix.1g规定单位为秒。
让客户知道服务器已经读其数据的一个方法时:调用shutdown(SHUT_WR)而不是调用close,并等待对方close连接的本地(服务器)端。
SO_OOBINLINE套接字选项
此选项打开时,带外数据将被保留在正常的输入队列中(即在线存放)。当发生这种情况时,接收函数的MSG_OOB标志不能用来读带外数据。
SO_RCVBUF和SO_SNDBUF套接字选项
每个套接字都有一个发送缓冲区和一个接收缓冲区,使用这两个套接口选项可以改变缺省缓冲区大小。
当设置TCP套接口接收缓冲区的大小时,函数调用顺序是很重要的,因为TCP的窗口规模选项是在建立连接时用SYN与对方互换得到的。对于客户,SO_RCVBUF选项必须在connect之前设置;对于服务器,SO_RCVBUF选项必须在listen前设置。
TCP套接口缓冲区的大小至少是连接的MSS的四倍,而必须是连接的MSS的偶数倍。
SO_RCVLOWAT和SO_SNDLOWAT套接字选项
每个套接字有一个接收低水位标记和一个发送低水位标记,他们由函数select使用。这两个选项可以修改他们。
接收低水位标记是让select返回“可读”而在套接口接收缓冲区中必须有的数据量,对于一个TCP或UDP套接口,此值缺省为1。发送低水位标记是让select返回“可写”而在套接口发送缓冲区中必须有的可用空间,对于TCP套接口,此值常为2048。
SO_RCVTIMEO和SO_SNDTIMEO套接字选项
使用这两个选项可以给套接口设置一个接收和发送超时。通过设置参数的值为0秒和0微秒来禁止超时。缺省时两个超时都是禁止的。
接收超时影响5个输入函数:read、readv、recv、recvfrom和recvmsg;发送超时影响5个输出函数:write、writev、send、sendto和sendmsg。
SO_REUSEADDR和SO_REUSEPORT套接字选项
SO_REUSEADDR提供如下四个功能:
1)SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
2)SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
3)SO_REUSEADDR允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
4)SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
SO_REUSEPORT选项有如下语义:
此选项允许完全重复捆绑,但仅在想捆绑相同IP地址和端口的套接口都指定了此套接口选项才性。
如果被捆绑的IP地址是一个多播地址,则SO_REUSEADDR和SO_REUSEPORT等效。
使用这两个套接口选项的建议:
在所有TCP服务器中,在调用bind之前设置SO_REUSEADDR套接口选项;
当编写一个同一时刻在同一主机上可运行多次的多播应用程序时,设置SO_REUSEADDR选项,并将本组的多播地址作为本地IP地址捆绑。
SO_TYPE套接字选项
该选项返回套接口的类型,返回的整数值是一个诸如SOCK_STREAM或SOCK_DGRAM这样的值。
SO_USELOOPBACK套接字选项
该选项仅用于路由域(AF_ROUTE)的套接口,它对这些套接口的缺省设置为打开(这是唯一一个缺省为打开而不是关闭的SO_xxx套接口选项)。当此套接口打开时,套接口接收在其上发送的任何数据的一个拷贝。
禁止这些回馈拷贝的另一个方法是shutdown,第二个参数应设为SHUT_RD。
函数fcntl提供了如下关于网络编程的特性:
1)非阻塞I/O:通过用F_SETFL命令设置O_NONBLOCK文件状态标志来设置套接口为非阻塞型。
2)信号驱动I/O:用F_SETFL命令来设置O_ASYNC文件状态标志,这导致在套接口状态发生变化时内核生成信号SIGIO。
3)F_SETOWN命令设置套接口属主(进程ID或进程组ID),由它来接收信号SIGIO和SIGURG。SIGIO在设置套接口为信号驱动I/O型时生成,SIGURG在新的带外数据到达套接口时生成。
4)F_GETOWN命令返回套接口的当前属主。
#include
int fcntl(int fd, int cmd, .../* int arg */);
/* 返回:若成功则取决于cmd,若出错则为-1 */
影响套接字描述符的两个标志:
O_NONBLOCK——非阻塞式I/O;
O_ASYNC——信号驱动式I/O。