美文网首页C/C++经验技巧总结
Linux下tcp连接断开后,端口释放问题

Linux下tcp连接断开后,端口释放问题

作者: XDgbh | 来源:发表于2018-05-07 11:16 被阅读420次

Linux系统下,TCP/IP连接断开

  • 如果客户端先断开连接,server端再断开,那么server端占用的端口号立马可以用。
  • 但是客户端未断开情况下,server自行关闭,那么占用的端口将进入TIME_WAIT状态而暂时不可使用,会以TIME_WAIT状态保留一定的时间(约为1-4分钟),然后才会释放端口。

TCP要保证在所有可能的情况下使得所有的数据都能够被投递。当你关闭一个socket时,主动关闭一端的socket将进入TIME_WAIT状态,而被动关闭一方则转入CLOSED状态,这的确能够保证所有的数据都被传输。当一个socket关闭的时候,是通过两端互发信息的四次握手过程完成的,当一端调用close()时,就说明本端没有数据再要发送了。这好似看来在握手完成以后,socket就都应该处于关闭CLOSED状态了。但这有两个问题,首先,我们没有任何机制保证最后的一个ACK能够正常传输,第二,网络上仍然有可能有残余的数据包(wandering duplicates),我们也必须能够正常处理。
通过正确的状态机,我们知道双方的关闭过程如下:

正常的四次挥手.png

假设最后一个ACK丢失了,服务器会重发它发送的最后一个FIN,所以客户端必须维持一个状态信息,以便能够重发ACK;如果不维持这种状态,客户端在接收到FIN后将会响应一个RST,服务器端接收到RST后会认为这是一个错误。如果TCP协议能够正常完成必要的操作而终止双方的数据流传输,就必须完全正确的传输四次握手的四个节,不能有任何的丢失。这就是为什么socket在关闭后,仍然处于 TIME_WAIT状态,因为他要等待以便重发ACK。
如果目前连接的通信双方都已经调用了close(),假定双方都到达CLOSED状态,而没有TIME_WAIT状态时,就会出现如下的情况。现在有一个新的连接被建立起来,使用的IP地址与端口与先前的完全相同,后建立的连接又称作是原先连接的一个化身。还假定原先的连接中有数据报残存于网络之中,这样新的连接收到的数据报中有可能是先前连接的数据报。为了防止这一点,TCP不允许从处于TIME_WAIT状态的socket建立一个连接。处于TIME_WAIT状态的socket在等待两倍的MSL时间以后(之所以是两倍的MSL,是由于MSL是一个数据报在网络中单向发出到认定丢失的时间,一个数据报有可能在发送图中或是其响应过程中成为残余数据报,确认一个数据报及其响应的丢弃的需要两倍的MSL),将会转变为CLOSED状态。这就意味着,一个成功建立的连接,必然使得先前网络中残余的数据报都丢失了。
由于TIME_WAIT状态所带来的相关问题,我们可以通过设置SO_LINGER标志来避免socket进入TIME_WAIT状态,这可以通过发送RST而取代正常的TCP四次握手的终止方式。但这并不是一个很好的主意,TIME_WAIT对于我们来说往往是有利的。

TIME_WAIT状态所带来的相关问题解决办法

Q: 我正在写一个unix server程序,不是daemon,经常需要在命令行上重启它,绝大
多数时候工作正常,但是某些时候会报告"bind: address in use",于是重启失
败。

A: Andrew Gierth
server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项,可以重用 端口。至于
TIME_WAIT状态,你无法避免,那是TCP协议的一部分。
使用setsockopt,比如 (XDgbh在linux下亲测有效)


int option = 1;
if ( setsockopt ( masterSocket, SOL_SOCKET, SO_REUSEADDR, &option,
sizeof( option ) ) < 0 )
{
die( "setsockopt" );
}


Q: 编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思?

A: 这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用
端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息,
指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧
使用同一端口,此时 SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期
望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不
可能。

一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端
口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组
还是唯一确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使
用 SO_REUSEADDR 选项。

可参考详细博文:
https://blog.csdn.net/yusiguyuan/article/details/21445773
https://blog.csdn.net/occupy8/article/details/50726019

相关文章

  • Linux下tcp连接断开后,端口释放问题

    Linux系统下,TCP/IP连接断开 如果客户端先断开连接,server端再断开,那么server端占用的端口号...

  • 理解TCP和UDP

    一、TCP端口 二、TCP报文结构 三、TCP连接的建立和释放 TCP的整个交互过程可总结为:先建立连接、然后传输...

  • 【TCP连接】与【HTTP请求】的相关面试问题详解

    【问题一】:现代浏览器在与服务器建立了一个 TCP 连接后是否会在一个 HTTP 请求完成后断开?什么情况下会断开...

  • tcp连接发起的http请求

    五个问题: 现代浏览器在与服务器建立了一个 TCP 连接后是否会在一个 HTTP 请求完成后断开?什么情况下会断开...

  • 关于TCP连接的一些知识点

    连接断开:Http 1.0默认会在请求结束后自动断开TCP连接,Http 1.1之后默认在请求头中添加了keep-...

  • TCP 与 UDP

    TCP 与 UDP(主要说TCP)TCP/UDP端口号TCP/UDP端口号TCP连接的建立TCP连接的建立发送se...

  • TCP10问

    1.TCP建立连接时需要几次握手, 断开连接需要几次握手? TCP建立连接需要三次握手, 断开连接要四次握手。现有...

  • LINUX下高效TCP端口转发工具--RINETD

    转自LINUX下高效TCP端口转发工具–RINETD#### rinetd 介绍 一个C语言开发的开源TCP端口...

  • Linux开放1521端口允许网络连接Oracle Listen

    Linux开放1521端口允许网络连接Oracle Listener症状:1. TCP/IP连接是通的。可以用pi...

  • HTTP 学习碎片

    持久连接 只要任意一端没有明确提出断开连接,那么保持TCP连接状态。这样做减少了TCP连接的重复建立和断开所造成的...

网友评论

    本文标题:Linux下tcp连接断开后,端口释放问题

    本文链接:https://www.haomeiwen.com/subject/cwkmrftx.html