TCP套接字选项()

1, getsockopt 和 setsockopt函数

getsockopt和setsockopt函数修改套接字的选项,fcntl函数可以用于将套接字设置为非阻塞套接字或者信号驱动套接字以及修改套接字属主的方法。

#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t* optlen);
int getsockopt(int sockfd, int level, int optname, void * optval, socklen_t * optlen);
// 成功返回0,出错返回-1
  • sockfd指向一个已经打开的套接字描述符。
  • level指定系统中解释选项的代码或者为通用套接字代码,或者为特定于协议的代码(如IPV4,IPV6,TCP,SCTP)。
  • optval为指向某个变量(*optval)的指针。

setsockopt从*optval中取得选项待设置的新值,getsockopt把以获取的选项当前值存放到 *optval中。

  • optlen指定optval参数的大小,对于setsockopt是一个值参数,对于getsockopt是一个值-结果参数。
#include <asm-generic/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>

void error_handling(const char* message);

int main(int argc,char*argv[]){
    int sock;
    int snd_buf = 1024*3,rcv_buf = 1024*3;
    int state;
    socklen_t len;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF,(void*)&rcv_buf,sizeof(rcv_buf));
    if(state)
        error_handling("setsockopt() error");

    state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF,(void*)&snd_buf,sizeof(snd_buf));
    if(state)
        error_handling("setsockopt() error");
    len = sizeof(snd_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF,(void*)&snd_buf,&len);
    if(state)
        error_handling("getsockopt() error");
    len = sizeof(rcv_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF,(void*)&rcv_buf,&len);
    if(state)
        error_handling("getsockopt() error");

    printf("Input buffer size: %d\n",rcv_buf);
    printf("Output buffer size: %d\n",snd_buf);
    return 0;
}

void error_handling(const char *message){
    fputs(message,stderr);
    fputc('\n',stderr);
    exit(1);
}
1.1 套接字的状态

有些时候,一些套接字选项的设置需要考虑到时序,比方说keep_alive什么

因此有一些套接字选项会继承自监听套接字(否则在连接完成到accept过程都没有设置)

包括有SO_DEBUG, SO_DONTROUTE, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVLOWAT, SO_SNDBUF, SO_SNDLOWAT
以上选项只需要配置在监听套接字上就可以

套接字选项分为两大基本类型:

  • 启动或禁止某个特性的二元选项(标志选项)
  • 取得并返回可以设置或检查的特定值的选项(值选项)。

标有“标志"的列指出一个选项是否为标志选项。标志列不含有".",相应选项用于在用户进程与系统之间传递所指定数据类型的值:

  • 当给这些标志选项调用getsockopt函数时,*optval是一个整数。 *optval中返回的值为0表示相应选项被禁止,不为0表示相应选项被启用。
  • setsockopt函数需要一个不为0的 *optval值来启用选项,一个为0的 *optval值禁止选项。

ip_mreq结构体

struct ip_mreq{
    struct in_addr imr_multiaddr;// 多播地址信息
    struct in_addr imr_interface;// 加入多播组的主机地址信息
}

示例:

[root@LW net_project]# cat Net_Option.cpp 
#include <unp.h>
#include <unp_base.c>
#include <netinet/tcp.h>

union val{
	int i_val;
	long l_val;
	struct linger linger_val;
	struct timeval timeval_val;
}val;

static char *sock_str_flag(union val *,int);
static char *sock_str_int(union val*,int);
static char *sock_str_linger(union val *,int);
static char *sock_str_timeval(union val *,int);

struct sock_opts{
	const char *opt_str;
	int opt_level;
	int opt_name;
	char *(*opt_val_str)(union val*,int);
};

static char strres[128];
static char* sock_str_flag(union val*ptr,int len){
	if(len != sizeof(int))
		snprintf(strres,sizeof(strres),"size (%d) not sizeof(int)",len);
	else
		snprintf(strres,sizeof(strres),"%s",(ptr->i_val == 0) ? "off":"on");
	return strres;
}


static char* sock_str_int(union val*ptr,int len){
	if(len != sizeof(int))
		snprintf(strres,sizeof(strres),"size (%d) not sizeof(int)",len);
	else
		snprintf(strres,sizeof(strres),"%s",(ptr->i_val == 0) ? "off":"on");
	return strres;
}

static char* sock_str_linger(union val*ptr,int len){
	if(len != sizeof(int))
		snprintf(strres,sizeof(strres),"size (%d) not sizeof(int)",len);
	else
		snprintf(strres,sizeof(strres),"%s",(ptr->i_val == 0) ? "off":"on");
	return strres;
}

static char* sock_str_timeval(union val*ptr,int len){
	if(len != sizeof(int))
		snprintf(strres,sizeof(strres),"size (%d) not sizeof(int)",len);
	else
		snprintf(strres,sizeof(strres),"%s",(ptr->i_val == 0) ? "off":"on");
	return strres;
}
sock_opts Sock_opts[] = {
	{"SO_BROADCAST", SOL_SOCKET,SO_BROADCAST,sock_str_flag},
	{"SO_DEBUG", SOL_SOCKET,SO_DEBUG, sock_str_flag},
	{"SO_DONTROUTE",SOL_SOCKET, SO_DONTROUTE,sock_str_flag},
	{"SO_ERROR",SOL_SOCKET,SO_ERROR, sock_str_int},
	{"SO_KEEPALIVE", SOL_SOCKET,SO_KEEPALIVE,sock_str_flag},
	{"SO_LINGER",SOL_SOCKET,SO_LINGER,sock_str_linger},
	{"SO_OOBINLINE",SOL_SOCKET,SO_OOBINLINE,sock_str_flag},
#ifdef SO_REUSEPORT
	{"SO_REUSEPORT",SOL_SOCKET,SO_REUSEPORT,sock_str_flag},
#else
	{"SO_REUSEPORT", 0,0,NULL},
#endif
	{"SO_TYPE",SOL_SOCKET,SO_TYPE,sock_str_int},
#ifdef SO_USELOOPBACK
	{"SO_USELOOPBACK",SOL_SOCKET,SO_USELOOPBACK, sock_str_flag},
#endif
	{"IP_TOS",IPPROTO_IP,IP_TOS,sock_str_int},
	{"IP_TTL",IPPROTO_IP,IP_TTL, sock_str_int},
	{"IPV6_DONTFRAG",IPPROTO_IPV6,IPV6_DONTFRAG,sock_str_flag},
	{"IPV6_UNICAST_HOPS",IPPROTO_IPV6,IPV6_UNICAST_HOPS,sock_str_int},
	{"IPV6_V6ONLY", IPPROTO_IPV6,IPV6_V6ONLY,sock_str_flag},
#ifdef TC_MAXSEG
	{"TCP_MAXSEG",IPPROTO_TCP,TC_MAXSEG,sock_str_int},
#endif
#ifdef TCP_NODELAY
	{"TCP_NODELAY",IPPROTO_TCP,TCP_NODELAY,sock_str_flag},
#endif
#ifdef SCTP_AUTO_CLOSE,SCTP_MAXBURST,SCTP_MAXSEG,SCTP_NODELAY
	{"SCTP_AUTOCLOSE",IPPROTO_SCTP,SCTP_AUTO_CLOSE,sock_str_int},
	{"SCTP_MAXBURST",IPPROTO_SCTP,SCTP_MAXBURST,sock_str_int},
	{"SCTP_MAXSEG",IPPROTO_SCTP,SCTP_MAXSEG,sock_str_int},
	{"SCTP_NODELAY",IPPROTO_SCTP,SCTP_NODELAY,sock_str_flag},
#endif
	{
		NULL,0,0,NULL
	},
};

int main(int argc,char **argv)
{
	int fd;
	socklen_t len;
	struct sock_opts *ptr;
	for(ptr = Sock_opts;ptr->opt_str != NULL;ptr++){
		printf("%s :",ptr->opt_str);
		if(ptr->opt_val_str == NULL)
			printf("(undefined)\n");
		else{
			switch(ptr->opt_level){
				case SOL_SOCKET:
				case IPPROTO_IP:
				case IPPROTO_TCP:
					fd = Socket(AF_INET,SOCK_STREAM,0);
					break;
#ifdef IPV6
				case IPPROTO_IPV6:
					fd = Socket(AF_INET6,SOCK_STREAM,0);
					break;
#endif
#ifdef IPPROTO_SCTP
				case IPPROTO_SCTP:
					fd = Socket(AF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);
					break;
#endif
				default:
					err_quit("Can't create fd for level %d\n",ptr->opt_level);
			}
			len = sizeof(val);
			if(getsockopt(fd,ptr->opt_level,ptr->opt_name,&val,&len) == -1)
				err_ret("getsockopt errpr");
			else
				printf("default = %s\n",(*ptr->opt_val_str)(&val,len));
			close(fd);
		}
	}
	return 0;
}

2, 通用套接字选项

  • SO_BROADCAST套接字选项

    开启或禁止进程发送广播消息的能力。只有数据报套接字支持广播,并且必须是在支持广播消息的网络上(如以太网,令牌环网),不可能在基于连接的传输协议上进行广播。只适用于UDP,在udp发布广播数据报之前必须配置该选项

  • SO_DEBUG套接字选项

    仅支持TCP,设置之后,TCP会在所有的发送、接收分组上保留详细跟踪信息,被保存在内核的某个环形缓冲区中,可以使用trpt程序检查

  • SO_DONTROUTE套接字选项

    规定绕过正常的路由机制。也就是说设置之后,将绕过路由表中网关的表项,在send,sendmsg,sendto中设置MSG_DONTROUTE有同样的效果

  • SO_ERROR套接字选项

    该套接字不能配置只能通过SO_ERROR获取

    如果套接字发生了错误,内核就会配置该套接字选项so_error为标准的Unix Exxx,称此错误为该套接字的待处理错误。而这会立刻通知到正在阻塞的select调用以及配置了信号驱动的套接字(会发送SIGIO信号)

    • 如果进程阻塞在对该套接字的select调用上,那么无论是检查可读条件还是可写条件,select均返回并设置其中一个或所有两个条件
    • 如果进程使用信号驱动式I/O模型,那就给进程或进程组产生一个SIGIO信号。

    read系统调用如果没有读到任何数据且SO_ERROR不为0,则会返回-1,errno设置为so_error配置值,之后so_error复位为0,如果so_error不为0但是有数据,那么会返回数据

    write被调用的时候如果so_error不为0,那么返回-1,errno设置为so_error配置值,之后so_error复位为0

  • SO_KEEPALIVE套接字选项

    设置SO_KEEPALIVE之后,如果两个小时套接字任意方向都没有数据交换,那么会发送一个存活确认分节 是一个对端必须响应的TCP分节。对此我们可能有四种结果,当然如果你仔细分析,你会发现这四个结果跟正常一个请求发送得到的结果很像:

    • 对端以期望的ACK正常响应,服务得不到任何反馈,2小时后继续发送分组
    • 对端以RST响应,告知本端TCP;对端已崩溃且已重新启动。该套接字的待处理错误被置为ECONNRESET,套接字本身则被关闭。
    • 对端对分节没有任何响应,内核会每隔75s发送一次分组,总共九次没有得到回应之后,关闭套接字,设置为ETIMEOUT

准确来说,该选项的作用在于检测主机的崩溃或者不可达,因为如果仅仅是进程崩溃的话,我们会收到FIN报文的,之所以说或者不可达,是因为存在一种可能是对端主机正常,但是路由崩溃了一段时间。

在CS框架下,一般来说比较常用与服务端,因为服务端相对来说比较稳定且可知,而客户端的话有可能因为种种原因没有切断连接,于是连接一直处于半开连接的状态,SO_KEEPALIVE可以提供一种解决方法

  • SO_LINGER套接字选项

    选项指定close函数对面向连接的协议(如TCP和SCTP)如何操作。默认操作是close立即返回,但是如果有数据残留在套接字发送缓冲区中,系统将试图把这些数据发送给对端。

    情形对端进程崩溃对端主机崩溃对端主机不可达
    本端TCP正在发送数据对端发送FIN报文,select条件可以感知到读条件。发送分组会收到RST报文,套接字关闭,如果继续(向套接字)写入,会发出SIGPIPE信号以及EPIPE错误没有收到回复,重复尝试之后触发ETIMEOUT 错误,套接字关闭tcp超时,套接字会触发EHOSTUNREACH错误
    本端TCP正在主动接收数据对端TCP发送FIN报文,本端收到一个EOF(可能在业务逻辑上属于过早)我们会(可能通过超时)停止接受数据我们会(可能通过超时)停止接受数据
    连接空闲,保持存活选项开启对端TCP发送FIN报文,select条件可以感知到读条件检测出来。两小时后发送9个保持存活检测分组,然后套接字的待处理错误被设置为ETIMEOUT两小时后发送9个保持存活检测分组,然后套接字的待处理错误被设置为EHOSTUNREACH
    连接空闲,未开启保持存活对端TCP发送FIN报文,select条件可以感知到读条件检测出来。

    可以通过SO_LINGER选项来改变这种行为,比方说我们可以丢掉所有发送缓冲区的数据并发送一个RST报文从而跳过time_wait阶段来复用端口(并不推荐,因为time_wait本身是为了避免出现幽灵分组问题才提出来的),或者我们可以让close稍微等一下(从而我们可以收到剩余发送的确认)
    SO_LINGER定义的行为是由struct linger决定的,linger(继续存留)

    #include <sys/socket.h>
    struct  linger {
    	int     l_onoff;                /* option on/off */
    	int     l_linger;               /* linger time */
    };
    

    setsockopt的调用将根据其中两个结构成员的值形成以下三种情形之一:

    • 如果l_onoff为0,关闭本选项。l_linger的值被忽略,TCP默认设置生效,close立即返回。
    • 如果l_onoff不为0,而l_linger为0,当close某个连接时TCP将中止该连接。就是说TCP将丢弃保留在套接字发送缓冲区中的任何数据,并发送RST给对端,没有通常的四分组连接终止序列。
    • 如果l_onoff为非0值且l_lingfeizuseer也为非0值,那么当套接字关闭时内核将拖延一段时间。如果在套接字发送缓冲区中仍残留有数据,那么进程将被投入睡眠,直到(a)有数据都已发送完且均被对方确认或(b)延滞时间到。如套接字被设置为非阻塞型,那么它将不等待close完成,即使延滞时间为非0也是如此。当使用SO_LINGER选项特性时,进程检查close的返回值非常重要,因为如果在数据发送完并被确认前延滞时间到的话close返回EWOULDBLOCK错误,且套接字发送缓冲区中的任何残留数据都被丢弃。

    下表汇总了对shutdown的两种可能调用和对close的三种可能调用,以及对TCP套接字的影响。

    函数说明
    shutdown,SHUT_RD在本套接字上不能再发出接收请求;进程仍可往套接字发送数据:套接字接收缓冲区中所有数据被丢弃;在接收到任何数据由TCP丢弃;对套接字发送缓冲区没有任何影响。
    shutdown,SHUT_WR在本套接字上不能再发出发送请求;进程仍可从套接字接收数据:套接字发送缓冲区中的内容被发送到对端,后跟正常的TCP连接终止序列(FIN);对套接字缓冲区无任何影响。
    close,l_onoff=0(默认情况)在套接字上不能再发出发送或接收请求: 套接字发送缓冲区中的内容被发送到对端。如果描述符引用计数为0: 在发送完发送缓冲区中的数据后,跟以正常的TCP连接终止序列(FIN),套接字接收缓冲区中内容被丢弃。
    close,l_onoff=1,l_linger=0在套接字上不能再发出发送或接收请求。如果描述符引用计数变为0,RST被发送到对端;连接的状态被置为CLOSED(没有TIME_WAIT状态);套接字发送缓冲区和套接字接收缓冲区中的数据被丢弃。
    close,l_onoff=1,l_linger != 0在套接字上不能再发出发送或接收请求。套接字发送缓冲区中的数据被发送到对端。如果描述符引用计数为0: 在发送完发送缓冲区中的数据后,跟以正常的TCP连接终止序列(FIN),套接字接收缓冲区中数据被丢弃;如果在连接变为CLOSED状态前延滞时间到,那么close返回EWOULDBLOCK错误。
  • SO_OOBINLINE套接字选项

    当开启本选项时,带外数据将被留在正常的输入队列中。这种情况下接收函数MSG_OOB来标志不能用来读带外数据。

  • SO_RCVBUF和SO_SNDBUF选项

    这两个顾名思义就是发送缓冲区大小和接收缓冲区大小了,期中接收缓冲区大小直接决定了建立连接的时候约定的窗口大小,根据TCP的流量控制,对端不会发送超过通告窗口大小的数据,如果对端无视窗口大小而发出了超过该窗口大小的数据,那么本端就会直接丢弃;但是对于UDP来说,由于没有流量控制,也就是无法控制对端发送的数据大小,从而可能导致数据报因为窗口小而被直接丢弃
    **两个套接字选项允许改变这两个缓冲区的默认大小。**如果主机支持NFS,那么UDP发送缓冲区的大小经常默认为9000字节左右一个值,而UDP接收缓冲区的大小则经常默认为40000字节左右一个值。

    设置缓冲区大小的函数调用顺序:

    1. TCP窗口规模选项是在建立连接时用SYN分节与对端互换得到的。对于客户,意味着SO_RECVBUF选项必须在调用connect之前设置;对于服务器,意味着该选项必须在调用listen之前给监听套接字设置。
    2. 给已连接套接字设置该选项对于可能存在的窗口规模选项没有任何影响,因为accept直到TCP的三路握手完成才会创建并返回已连接套接字。这就是必须给监听套接字设置本选项的根本原因。(套接字缓冲区的大小总是由新创建的已连接套接字从监听套接字继承而来)。

    TCP套接字缓冲区大小至少是相应连接的MSS值的四倍。对于单项数据传输(比如单方面的文件传输),当说"套接字缓冲区大小"时,指的是发送端主机上的套接字发送缓冲区大小和接收端主机上的套接字接收缓冲区大小。对于双项数据传输,在发送端指的是收发两个套接字缓冲区的大小,在接收端也是指收发两个套接字缓冲区的大小。

    设置大小的约束条件

    1. 由于快速恢复要求连续发送三个相同的确认,因此要求接收端至少能容纳四个分组(比方说j,j+2,j+3,j+4触发了三个相同的确认),才能激活快速恢复算法, 所以要求缓冲区大小至少为MSS的四倍
    2. 一般要求是整数倍(或者是偶数倍),多余的并不能得到使用
    3. 窗口大小会影响性能,我们可以用带宽(单位bit/s)乘以延迟(单位s)从而计算得到带宽延迟积,其实际含义有点像是满带宽下发送端最大未确认的数据大小,如果窗口大小小于该值,则不能满带宽运行
  • SO_RCVLOWAT和SO_SNDLOWAT套接字选项

    用于让select判断可读和可写,默认情况下,SO_RCVLOWAT是1,SO_SNDLOWAT是2048。

    接收低水位标记是让select返回"可读"时套接字接收缓冲区中所需的数据量。对于TCP,UDP,SCTP套接字,其默认值为1,发送低水位标记是让select返回"可写"时套接字发送缓冲区中所需的可用空间。

    UDP虽然也有低水位的概念,但是由于UDP套接字的发送缓冲区大小不会改变(因为UDP并不为由应用进程传递给它的数据报保留副本)所以只要设定的发送缓冲区大小大于发送低水位,那么UDP就一定是可写的

  • SO_RCVTIMEO和SO_SNDTIMEO套接字选项

    两个选项允许给套接字的接收和发送设置一个超时值。该套接字设置的时候使用的是timeval结构体指针,与select所用参数相同。可以指定我们读取和发送的超时值,默认是0s和0μs,默认情况下这两个超时都是禁止的。

    接收超时影响5个输入函数: read,readv,recv,recvfrom,recvmsg

    发送超时影响5个输出函数: write,writev,send,sendto,sendmsg

  • SO_REUSEADDR和SO_REUSEPORT套接字选项

    SO_REUSEADDR允许我们重用地址和端口,他可以应用于以下的场景

    1. SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将该端口用作它们的本地端口的连接仍存在。

      假设说有一个服务器在遇到新的连接请求的时候通过派生子进程来处理,那么如果中途停止重启(此时子进程仍然在服务),如果不设定SO_REUSEADDR,bind会因为子进程占用端口而失败,通过在socket和bind之间设置SO_REUSEADDR选项,我们可以避免该问题,所有的tcp服务器都应该指定该选项

    2. SO_REUSEADDR允许我们在同一端口启动同一服务器的多个实例,只要每个实例捆绑一个不同的IP地址即可。对于使用IP别名技术托管多个HTTP服务器的网点(site)来说很常见。(详情看书166页)

      对于TCP,绝不可能启动捆绑相同IP地址和相同端口号的多个服务器:这是完全重复的捆绑。(不能再相同的ip地址和端口在启动一个服务器)。

      有些操作系统不允许对已经绑定了通配地址的端口再捆绑任何"更为明确的"地址,也就是不论是否预先设置SO_REUSEADDR,系统的bind调用都会失败,这样的系统上,执行通配地址捆绑的服务器进程必须最后一个启动。

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

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

      本特性用于多播时,允许在同一个主机上同时运行同一个应用程序的多个副本。

  • SO_REUSEPORT的特性:

    • 选项允许完全重复的捆绑,不过只有在想要捆绑同一IP地址和端口的每个套接字都指定了本套接字选项才行。
    • 如果被捆绑的IP地址是一个多播地址,那么SO_REUSEADDR和SO_REUSEPORT被认为是等效的。

    此选项的问题在于并非所有系统都支持。

  • SO_TYPE套接字选项

    选项返回套接字的类型,返回的整数值时一个诸如SOCK_STREAM或SOCK_DGRAM的值,本选项通常由启动时继承了套接字的进程使用。

  • SO_USELOOPBACK套接字选项

    仅用于路由域(AF_ROUTE)的套接字。对于这些套接字,默认设置为打开(这是唯一一个默认值为打开而不是关闭的SO_XXX二元套接字选项)。当本选项开启时,相应套接字将接收在其上发送的任何数据报的一个副本。

3, IPV4套接字选项

由IPV4处理,级别为IPPROTO_IP。

  • IP_HDRINCL套接字选项

    选项是给一个原始套接字设置的,必须为所有在该原始原始套接字上发送的数据报构造自己的IP首部。一般来说,IP首部是内核构造的,但是启用该选项的话,将由应用程序构造自己的IP首部以取代IP置于该首部中的某些手段。

    当开启选项后,构造完整的IP首部,以下情况除外:

    1. IP总是计算并存储IP首部校验和

    2. 如果将IP标识字段置为0,内核将设置该字段

    3. 如果源地址是INADDR_ANY,IP将把它设置为外出接口的主IP地址。

    4. 如果设置IP选项取决于实现。有些实现取出预先使用IP_OPTIONS套接字选项设置的任何IP选项,把它们添加到构造的首部中,而其它实现则要求亲自在首部指定任何期望的IP选项。

    5. IP首部有些字段必须以主机字节序填写,有些字段必须以网络字节序填写,具体取决于实现。使得利用本套接字选项编排原始分组的代码不像期待的那样便于移植。

  • IP_OPTIONS套接字选项

    选项设置允许在IPV4首部中设置IP选项,要求熟悉IP首部中IP选项的格式。

  • IP_RECVDSTADDR套接字选项

    启用该套接字后,UDP数据报的目的ip地址将由recvmsg函数作为辅助数据返回

  • IP_RECVIF套接字选项

    启动此选项将导致所收到UDP数据报的接收接口索引由recvmsg函数作为辅助数据返回。

  • IP_TOS套接字选项

    启动此选项允许为TCP,UDP,SCTP套接字设置IP首部中的服务类型字段(图A-1包含DSCP,ECN子字段)。如果给本选项调用getsockopt,那么用于放入外出IP数据报首部的DSCP和ECN字段中的TOS当前值(默认为0)将返回。没有办法从接收到IP数据报中取得值。(详情看书)

  • IP_TTL套接字选项

    可以使用本选项设置或获取系统用在从某个给定套接字发送的单播分组上的默认TTL(分节存活时间)值。(多播TTL值使用IP_MULTICAST_TTL套接字选项设置)。tcp和udp套接字默认是64,原始套接字默认值是255

ICMPV6套接字选项
  • ICMP6_FILTER套接字选项

    本选项允许获取或设置一个icmp6_filter结构,结构指出256个可能的ICMPv6消息类型中哪些将经由某个原始套接字传递给所在进程。

剩下选项看书最为妥当,以后的自己还是把书带在身边。

IPV6套接字选项

169页

TCP套接字选项

171页

SCTP套接字选项

173页

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值