[C++ 网络协议] 套接字的多种可选项

目录

[1. 套接字的可选项](#1. 套接字的可选项)

[2. 获取/设置套接字可选项](#2. 获取/设置套接字可选项)

[2.1 getsockopt函数(获取套接字可选项)](#2.1 getsockopt函数(获取套接字可选项))

[2.2 setsockopt函数(设置套接字可选项)](#2.2 setsockopt函数(设置套接字可选项))

[3. 常用套接字可选项](#3. 常用套接字可选项)

[3.1 SOL_SOCKET协议层的SO_TYPE可选项](#3.1 SOL_SOCKET协议层的SO_TYPE可选项)

[3.2 SOL_SOCKET协议层的SO_SNDBUF和SO_RCVBUF可选项](#3.2 SOL_SOCKET协议层的SO_SNDBUF和SO_RCVBUF可选项)

[3.3 SOL_SOCKET协议层的SO_REUSEADDR可选项](#3.3 SOL_SOCKET协议层的SO_REUSEADDR可选项)

[3.3.1 Time-wait状态](#3.3.1 Time-wait状态)

[3.3.2 SO_REUSEADDR可选项](#3.3.2 SO_REUSEADDR可选项)

[3.4 IPPROTO_TCP协议层的TCP_NODELAY可选项](#3.4 IPPROTO_TCP协议层的TCP_NODELAY可选项)

[3.4.1 Nagle算法](#3.4.1 Nagle算法)

[3.4.2 TCP_NODELAY可选项](#3.4.2 TCP_NODELAY可选项)


1. 套接字的可选项

SOL_SOCKET:是套接字相关的通用可选项。

IPPROTO_IP:是IP协议相关事项。

IPPROTO_TCP:是TCP协议相关的事项。

无需全部记忆下来,只有一些是常用的,下面将会介绍。

2. 获取/设置套接字可选项

2.1 getsockopt函数(获取套接字可选项)

cpp 复制代码
LINUX:
#include<sys/socket.h>

int getsocketopt(
int sock,                //用于查看选项套接字文件描述符
int level,               //要查看的可选项的协议层
int optname,             //要查看的可选项名
void* optval,            //保存查看结果的缓冲地址值
socklen_t* optlen        //向第四个参数optval传递的缓冲大小,即第四个参数所占字节数
);
成功返回0,失败返回-1

WINDOWS:
#include<winsock2.h>

int getsockopt(
SOCKET sock,              //同上    
int level,                //同上
int optname,              //同上
char* optval,             //同上,不同的是,这里是char* 类型要进行强制转换
int* optlen               //同上,不同的是,这里是int* 类型
);
成功返回0,失败返回SOCKET_ERROR

2.2 setsockopt函数(设置套接字可选项)

cpp 复制代码
LINUX:
#include<sys/socket.h>

int setsockopt(
int sock,            //用于更改可选项的套接字文件描述符
int level,           //要更改的可选项协议层
int optname,         //要更改的可选项名
const void* optval,  //保存要更改的选项信息的缓冲地址值
socklen_t optlen     //向第四个参数optval传递的可选项信息的字节数
);
成功返回0,失败返回-1

WINDOWS:
#include<winsock2.h>

int setsockopt(
int sock,            //同上
int level,           //同上
int optname,         //同上
const char* optval,  //同上,不同的是这里是const char* 类型
int optlen           //同上,不同的是这里是int 类型
);
成功返回0,失败返回SOCKET_ERROR

3. 常用套接字可选项

3.1 SOL_SOCKET协议层的SO_TYPE可选项

作用:用以查看套接字类型。如果是TCP套接字则为1(SOCK_STREAM),UDP套接字则为2(SOCK_DGRAM)。

注意:套接字类型不可更改,只能在创建时决定,由表也可得知。

3.2 SOL_SOCKET协议层的SO_SNDBUF和SO_RCVBUF可选项

作用:用以查看/修改输入/输出缓冲区大小。

注意:当你修改完后的I/O缓冲区大小,可能不是和你设置的结果一样,这是因为,缓冲区的大小设置要谨慎处理,不会完全按我们的要求进行,我们只是向系统传递要求,系统不一定会按照我们的结果来设置。

3.3 SOL_SOCKET协议层的SO_REUSEADDR可选项

3.3.1 Time-wait状态

在了解SO_REUSEADDR可选项之前,先介绍套接字的Time_wait状态。

Time_wait状态:就是当某一方向另一方发起断开连接请求时,经过四次握手状态,请求断开连接的这一方在接收到另一方发来的FIN信息时,就会进入到一个Time-wait状态,等状态结束,才会关闭套接字,在这个期间,端口是一直处在运行状态,不能绑定其它套接字。

如图所示,只有先请求断开的这一方,才会经过Time-wait状态。

所以,假设服务器端是先请求断开的这一方,那么服务器端在与客户端进行四次握手后,进入到Time-wait状态,这时,服务器端不能马上重新运行,因为下次运行,进行IP地址和端口号绑定时,bind函数会发生错误,因为此时套接字还处于Time-wait状态,端口号仍然在使用中,所以服务器不能马上重新运行。

1.客户端套接字为什么先请求断开,重启后仍然可以立马运行?

因为:客户端的端口是动态分配的,并不是固定的。
2.客户端套接字会不会经过Time-wait状态?

答:会的,只要是先请求断开的这一方的套接字,都会经过Time-wait状态。
3.为什么会有Time-wait这个状态?

答:假设上述图中,主机A在发送完最后一个数据包后,马上关闭套接字,而最后一个数据包并没有送达到主机B,那么此时主机B就会认为前一个数据包发送给了主机A,而主机A没有收到,就会把前一个主机包进行重传,但是,主机A却再也不能接收到这个数据包了,因为主机A已经在发送最后一个数据包的同时把套接字给关闭了。基于这些考虑,才会有Time-wait状态。

3.3.2 SO_REUSEADDR可选项

Time-wait状态,看起来很重要,但并不是那么让人喜欢。当系统发生故障紧急停止时,需要立马重启服务器端,提供服务,这时,因为服务器端的套接字处于Time-wait状态,从而导致,必须要等待几分钟。如图:

此时,服务器端每接收到主机B发来的数据包,Time-wait状态就会进行重置,服务器端就必须要等待状态结束。

所以,我们提供SO_REUSEADDR可选项,来设置套接字。

作用:调整参数,将允许处于Time-wait状态的套接字绑定的端口号,绑定新的套接字。

值:默认值是0(假),不允许Time-wait状态的套接字的端口号绑定新的套接字,设置为1(真),将允许绑定新的套接字。

3.4 IPPROTO_TCP协议层的TCP_NODELAY可选项

3.4.1 Nagle算法

在了解TCP_NODELAY可选项的作用之前,先了解Nagle算法。

Nagle算法优点:防止因数据包过多而发生的网络过载。

Nagle算法缺点:因要等待ACK消息,传输速率会降低。

Nagle算法原理:只有收到前一数据的ACK消息时,才发送下一数据。如图:

主机A发送字符串"Nagle"到主机B。

左边,当开启了Nagle算法时,主机A会先将头字符N存入输出缓冲中,这时因为N是头字符,没有需要接收的ACK,所以会立马传输给主机B,接着主机A等待主机B的ACK,在等待的同时,会将余下的字符存入输出缓冲里,在接收到主机B的ACK消息后,把余下字符装入一个数据包发送给主机B。这时,总共只传递了4个数据包。

右边,当关闭了Nagle算法时,极端情况下(并不是说关闭Nagle算法一定是这么传输的),主机A有可能会逐个字符依次传到输出缓冲里,因为无需等待主机B的ACK,在存入输出缓冲里,就马上传输给主机B。这样,总共传递了10个数据包。

综上,Nagle算法可以防止数据包过多而导致的网络过载。

Nagle算法在什么情况下适用,什么情况下不适用?

答:要根据传输数据的特性来,网络流量未受太大影响时,不使用Nagle算法要更快。比如:大文件数据的传输,这时即便不使用Nagle算法也会在装满输出缓冲时再进行传输,这样不仅不会增加数据包的数量,反而因为不用接收ACK,而提高传输速度。

3.4.2 TCP_NODELAY可选项

我们可以通过TCP_NODELAY来禁用Nagle算法。

作用:启用/禁用Nagle算法。

值:默认值是0(假)启用Nagle算法,1(真)禁用Nagle算法。

相关推荐
ITxiaobing20237 小时前
中国公司海外广告投放的 IP 地址库选型:从“查归属”到“验真实”的工程视角
网络·网络协议·tcp/ip
xiaoye-duck8 小时前
《C++ 工具库实战》gflags 命令行参数解析库详解
c++·第三方库
狂奔的sherry8 小时前
C++ 宏生成访问函数的代价:访问权限、调试和类型检查
c++·宏·编译·预处理器·类型检查
划破黑暗的第一缕曙光10 小时前
[C++]:5.STL:string(2)
java·c++·redis
明天也要努力学习12 小时前
TCP 协议的相关特性
网络·网络协议·tcp/ip
小超人诞生日记12 小时前
C++ 异常机制详解:从抛出捕获到异常安全
c++·算法
SHENGWEI胜为13 小时前
局域网出现 IP 地址冲突怎么办?如何从 ARP 表定位故障设备
网络协议·tcp/ip·php
多弗朗皮卡丘13 小时前
C++的IO流
开发语言·c++·io流·文件io流
2401_8734794013 小时前
源IP告警太多用什么工具分层?ASN与风险评分操作指南
网络·网络协议·tcp/ip
xiangyun6114 小时前
C++ 手撕 shared_ptr:引用计数与控制块到底长什么样?
开发语言·c++·算法·面试·stl