0
点赞
收藏
分享

微信扫一扫

TCP/IP网络编程笔记-ch9.套接字的各种可选项

清冷的蓝天天 2022-01-20 阅读 31

文章目录

函数

对套接字的可选项进行读取

#include<sys/socket.h>

@param sock:用于查看选项套接字文件描述符
@param levl:要查看的可选项的协议层
@param optname:要查看的可选项名
@param optval:保存查看结果的缓冲地址值
@param optlen:向第四个参数optval传递的缓冲大小。调用函数后,该变量保存通过第四个参数的可选项信息的字节数
int getsockopt(int sock,int level,int opname,void *optval,socklen_t *optlen);
//成功返回0,失败返回-1

设置套接字的可选项

#include<sys/socket.h>

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

知识点

套接字可选项和I/O缓冲大小

套接字多种可选项,之前的程序是创建好套接字(无特别操作)直接使用的,此时通过默认的套接字特性进行数据通信。但有时候需要对套接字特性进行更改。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RzNiNr68-1642498675472)(https://note.youdao.com/yws/res/9/WEBRESOURCEdad93246acbba216885921f1ec193d29)]

由表可知,套接字选项是分层的。IPPROTO_IP层可选项是IP协议相关,IPPROTO_TCP层是TCP协议相关,SOL_SOCKET层是套接字相关的通用可选项。
实际能设置的可选项数量还不止上表这些,实际使用中逐一掌握即可。

SO_REUSEADDR

在学习SO_REUSEADDR可选项前,应理解好Time-wait状态。
在客户端控制台调用close函数时,向服务器端发送FIN消息并结果四次握手过程,输入CTRL+C时也会向服务器端传递FIN消息。强制终止程序时,由操作系统关闭文件及套接字,此时相当于调用close函数,也会向服务器端传递FIN消息。

因为通常是由客户端先请求断开连接,所以不会发生特别的事情。重启服务器端也不成问题。
但下方式则不同:

服务器端和客户端已经建立连接的状态下,向服务器端控制台输入CTRL+C,强制关闭服务器端

此时服务器端向客户端发送FIN消息。以此方式终止程序,则服务器重新运行时将产生问题。如果用同一端口号重新运行服务器端,将输出"bind()error"消息,且不能再次运行。这时,等待大约3分钟即可重新运行服务器端(这3分钟即为Time-wait状态的时间)。

Time-wait

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eNdPZ8MC-1642498675472)(https://note.youdao.com/yws/res/9/WEBRESOURCE3f598197bd83a4ae57d3e85424bd16a9)]

上图中A是服务器端,主机A向B发送FIN消息,即同于服务器端在控制台输入CTRL+C,但套接字在经过四次握手过程后并非立即消除,而是经过一端时间的Time-wait状态。(只有先断开连接的(先发送FIN消息的))主机才经过Time-wait状态。故如果服务器端先断开连接,则无法立即重新运行。因为套接字处于Time-wait过程时,相应端口正在使用。故此时调用bind函数会发生错误。

为什么客户端不考虑Time-wait过程?

不论是服务器还是客户端均存在Time-wait过程,只要是先断开的套接字都会经历Time-wait过程,但不需考虑客户端Time-wait状态,
因为客户端套接字的端口号是任意指定的,不同于服务器端客户端每次运行时会动态分配端口号,故无需关注其Time-wait带来的影响。

TIme-wait存在的意义?

当先断开连接的套接字向对方传输ACK消息时,为防止最后的ACK消息在传输过程中丢失,套接字处于Time-wait状态,如果丢失了则重传ACK消息。
这样对方主机也能正常终止。

解决Time-wait?(即使服务器刚刚关闭也能重新打开该端口)

地址再分配
Time-wait看似重要却不一定令人人都满意。
当网络状态不理想时,如果最后的数据丢失,对方重新传送FIN消息,这边也重传ACK消息,这样可能Time-wait状态会一直持续下去。

解决方案为在套接字的可选项中更改SO_REUSEADDR的状态,调整该参数,可将Time-wait状态下的套接字端口号重新分配给新的套接字。
SO_REUSEADDR默认为0(假),将其改为1(真)即可分配Time-wait状态下的套接字端口。

使用过程:
optlen=sizeof(option);
option=TRUE;
setsockopt(serv_sock,SOL_SOCKET,SO_REUSEADDR,(void *)&option,optlen);

TCP_NODELAY

Nagle算法

为防止数据包过多产生网络过载,Nagle算法于1984年诞生。它应用于TCP层,非常简单。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GHC9P8ah-1642498675472)(https://note.youdao.com/yws/res/e/WEBRESOURCE1e67b8a60b2e60fecba4bb862d35c57e)]

Nagle算法与未使用Nagle算法差别:

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

TCP套接字默认使用Nagle算法交换数据,因此最大限度地进行缓冲,直到收到ACK。
如:发送Nagle时

Nagle:N+agle(两个发送数据包,agle等收到N时才发送出去,两个接收数据包(ACK))
非Nagle:N+a+g+l+e(5个发送数据报,数据到达输出缓冲即被发送,不等待ACK,5个接收数据包(ACK))(此为五个字母隔一段时间到达输出缓存的情况,并非每个包只能穿一个字母)

Nagle并非什么时候都适用,当网络流量未受太大影响时,不适用Nagle算法相较于适用传输速度更快。经典的是"传输大文件数据"。不使用Nagle算法也会在装满输出缓冲时传输数据包,此时不仅不会增加数据包数量,反而不需等待ACK就能连续除数,可大大提高传输速度。

一般不适用Nagle可提高传输速度,但无条件放弃Nagle算法会增加过多的网络流量,影响传输,所以没有准确判断数据特性时不应禁用Nagle算法。

如何禁用Nagle算法?

将套接字可选项TCP_NODELAY改为1(真)即可

禁用:
int opt_val=1;
setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(void *)&opt_val,sizeof(opt_val));

查看Nagle算法设置情况:
int opt_val;
socklen_t opt_len;
opt_len=sizeof(opt_val);
getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(void *)&opt_val,&opt_len);

实例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yOQ1JBjB-1642498675473)(https://note.youdao.com/yws/res/6/WEBRESOURCE36977626fea2cf0ba3d9789f079450c6)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IWxoaIFA-1642498675473)(https://note.youdao.com/yws/res/c/WEBRESOURCE516d47eb722d2eeeb080861dfcb59bbc)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vZzo2EMg-1642498675473)(https://note.youdao.com/yws/res/e/WEBRESOURCEcbf7ec74b1cf31acc67afbcbe31fcfde)]

举报

相关推荐

0 条评论