UNP-套接字选项

Posted perfy576

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UNP-套接字选项相关的知识,希望对你有一定的参考价值。

第7章 套接字选项

7.1 获取和设置选项

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

 

其中optval是0或是非0值表示是否开启,其他结构提表示设置值

 

7.2 level:SOL_SOCKET

7.2.1 SO_BROADCAST

optval:int类型

是否允许广播

不能再基于连接的传输协议和点对点链路上进行广播

应用程序在发送广播数据包之前必须设置本套接字选项,能够有效的防止一个进程在其应用程序本没有设计成可广播的时候,发送广播数据报.

如果没有设置SO_BROADCAST选项,返回EACCES错误

7.2.2 SO_DONTROUTE

int

套接字外出分组逃过底层协议的正常路由选路.

通常是在一个子网直连网络上.

如果不是在直连网络上,而又设置了该选项,返回ENETUNREACH错误

这个选项和send,`sendto,sendmsg使用了MSG_DONTROUTE选项是相同的结果.

7.2.3 SO_ERROR

int

当套接字出现错误的时候,使用该选项,获取错误值,内核so_error变量

当套接字出现错误的时候,则该套接字为待处理错误:

  • 多路复用下,该套接字可读可写

  • 信号驱动下,SIGIO信号

当read套接字的时如果没有读到数据,同时so_error非0,则read返回so_error的值(而非0),同时内核重置so_error

write时,如果so_error非0,则返回so_error,同时内核重置so_error

so_error的值为标准的error中的一个.

7.2.4 SO_KEEPALIVE

int

保活选项.

Tcp定时给对端发送保活探测分节:

  • 对端回复ACK,表示连接正常

  • 对端RST回复,表示对端已经崩溃重启

    so_error为ECONNRESET套接字本身被关闭

  • 没有相应,超时后放弃,

    so_error为ETIMEOUT

    如果收到了ICMP主机不可达的报文,表示对端主机没有崩溃只是不可达,此时so_error为EHOSTUNREACH

    这种情况是可能为对端主机崩溃,或是网络故障.

如果想要更改保活探测时间,不能从这两个函数中修改,应该修改系统的参数,此时对所有套接字起效(修改时间时).

7.2.5 SO_LINGER


struct linger
{
 int l_onoff; // 0 关闭,非0,开启
 int l_linger; //单位秒
};

表示,在close套接字的时候,在发送缓冲区的数据,如果和处理

  1. 00

    表示关闭,此时执行默认操作,close立即返回发送缓冲区的数据被发送出去,发送完毕后发送FIN分节关闭套接字(套接字引用计数为0时,也就是只有这个描述符关联了这个套接字)

    第一个为0时,忽略第二个值

  2. 10

    开启了选项,同时不等待数据发送完毕

    close直接返回,发送RST分节,套接字状态直接到CLOSED,不进入TIME_WAIT阶段

  3. 1n

    开启选项,同时设置等待事件

    close阻塞直到发送完毕正常返回,如果指定时间内没有发送完,那么close返回EWOULDBLOCK错误.数据被丢弃

7.2.5 SO_RCVBUF SO_SNDBUF

int

每个套接字都有发送和接受缓冲区.

TCP的SO_RCVBUF是窗口通告大小,udp的则是接收到的数据不能放到缓冲区就丢弃

TCP连接在三次握手时交换窗口大小,因此需要在connect和listen之前设置该选项

TCP套接字缓冲区至少为MSS的四倍,而且为双数倍,原因在于,tcp双工,在一个管道中发送的包数量应该等于相反方向管道中ACK的数量,那么发送缓冲区的MSS就是双数倍大小,存在2n个待确认的包.

7.2.6 SO_RCVLOWAT SO_SNDLOWAT

IO复用用的何时需要唤醒一个套接字可读和可写

SO_RCVLOWAT一般都为1

SO_SNDLOWAT:TCP为2048.udp因为发送不需要保存副本,因此只要只要发送缓冲区大小大于套接字低水位标记,udp总是可写

7.2.7 SO_REUSEADDR

int

linux中,只要一个端口正在使用,也就是说端口上有链接,那么就不能在该端口上启动另一个连接

S_REUSEADDR:

  1. 允许一个监听服务器绑定在一个已经存在连接的本地端口上(此时该链接不是监听连接,而一个服务连接)

    主要在于让bind成功

  2. 同一端口启动同一服务器的多个实例,只要ip不同即可

  3. 允许单进程绑定同一端口到多个套接字上,只要本地ip地址不同即可

  4. 协议允许的话,相同的ip和端口可已绑定在同一套接字上

这里的套接字都是只外出,监听的套接字,也就是说,用了同一台电脑的同一协议端口,(可能)同一ip地址

需要在bind之前设置

对于bind到同一端口的不同ip的进程,数据包如何分配的问题,是更加通用的优先获得.最后再分给最通用的

7.2.8 SO_REUSEPORT

int

  1. 允许重复ip和端口绑定

    但是必须这些套接字都开启了该选项

  2. 如果是一个多播地址,那么SO_REUSEADDR == SO_REUSEPORT

7.2.9 SO_TYPE

int

返回套接字类型

7.3 level:IPPEOTO_IP

ipv4套接字选项

7.3.1 IP_HDRINCL

int

应用于原始套接字.是否需要我们手动构造ip头部,开启表示我们手动构造.

开启是内核为我们构造的是:

  1. ip首部校验和

  2. ip标识字段为0,内核为构造

  3. ip源地址为INADDR_ANY,内核填充

  4. 设置的ip选项,内核填充

诸暨序和网络序手动确定

7.3.2 IP_OPTIONS

int

是否允许设置ip选项

7.3.3 IP_TTL

int

设置TTL

7.4 level:IPPROTO_TCP

7.4.1 TCP_MAXSEG

int

设置TCP连接最大分节大小MSS.

该选项必须在connect之前,因为MSS是在SYN中告诉对端

7.4.2 TCP_NODELAY

int

是否禁用nagle算法.

在接收到ACK之前,那么任何小于MSS的报文将被组合为一个MSS,在收到ACK后发送,因此是一种等停式的传输.

nagle与延时ACK构成短暂的死锁.

 

SO_REUSEADDR和SO_REUSEPORT区别

SO_REUSEADDR主要改变了系统对待通配符IP地址冲突的方式。

如果不用SO_REUSEADDR的话,如果我们将socketA绑定到0.0.0.0:21,那么任何将本机其他socket绑定到端口21的举动(如绑定到192.168.1.1:21)都会导致EADDRINUSE错误。因为0.0.0.0是一个通配符IP地址,意味着任意一个IP地址,所以任何其他本机上的IP地址都被系统认为已被占用。如果设置了SO_REUSEADDR选项,因为0.0.0.0:21192.168.1.1:21并不是完全相同的地址端口对(其中一个是通配符IP地址,另一个是一个本机的具体IP地址),所以这样的绑定是可以成功的。需要注意的是,无论socketAsocketB初始化的顺序如何,只要后一个设置了SO_REUSEADDR,绑定都会成功;而只要没有设置SO_REUSEADDR,绑定都不会成功。

 

SO_REUSEPORT

基本上来说,SO_REUSEPORT允许我们将任意数目的socket绑定到完全相同的源地址端口对上,只要所有之前绑定的socket都设置了SO_REUSEPORT选项。如果第一个绑定在该地址端口对上的socket没有设置SO_REUSEPORT,无论之后的socket是否设置SO_REUSEPORT,其都无法绑定在与这个地址端口完全相同的地址上。除非第一个绑定在这个地址端口对上的socket释放了这个绑定关系。与SO_REUSEADDR不同的是 ,处理SO_REUSEPORT的代码不仅会检查当前尝试绑定的socket的SO_REUSEPORT,而且也会检查之前已绑定了当前尝试绑定的地址端口对的socket的SO_REUSEPORT选项。如果当前一个socket没有设置SO_REUSEPORT已经处于TIME_WAIT阶段,而这个设置了SO_REUSEPORT选项的新socket尝试绑定到当前地址,这个绑定操作也会失败。

 

以上是关于UNP-套接字选项的主要内容,如果未能解决你的问题,请参考以下文章

UNP学习第六章

UNP——第三章,套接字编程介绍

UNP——第二章,传输层

UNP——第二章,端口号,套接字对,TCP,UDP输出

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

UNP卷一学习笔记:基本UDP套接字编程