`

如何优雅地关闭一个socket

    博客分类:
  • IOCP
阅读更多
如何优雅地关闭一个socket 收藏

    最近在windows编程时需要考虑到“如何优雅地关闭一个socket”,查阅了一些资料,现将查到的相关资料做个汇编,希望能对后来者有所帮助(比较懒,所以英文资料没有翻译:-))

1. 关闭Socket时究竟做了什么

    关闭socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况。前者是指有本地主机主动发起的关闭;而后者则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接。
    其状态图如下图所示:

      起初每个socket都是CLOSED状态,当客户端初使化一个连接,他发送一个SYN包到服务器,客户端进入SYN_SENT状态。
服务器接收到SYN包,反馈一个SYN-ACK包,客户端接收后返馈一个ACK包客户端变成ESTABLISHED状态,如果长时间没收到SYN-ACK包,客户端超时进入CLOSED状态。
  当服务器绑定并监听某一端口时,socket的状态是LISTEN,当客户企图建立连接时,服务器收到一个 SYN包,并反馈SYN-ACK包。服务器状态变成SYN_RCVD,当客户端发送一个ACK包时,服务器socket变成ESTABLISHED状态。

  当一个程序在ESTABLISHED状态时有两种图径关闭它, 第一是主动关闭,第二是被动关闭。如果你要主动关闭的话,发送一个FIN包。当你的程序closesocket或者shutdown(标记),你的程序发送一个FIN包到peer,你的socket变成FIN_WAIT_1状态。peer反馈一个ACK包,你的socket进入FIN_WAIT_2状态。如果peer也在关闭连接,那么它将发送一个FIN包到你的电脑,你反馈一个ACK包,并转成TIME_WAIT状态。
  TIME_WAIT状态又号2MSL等待状态。MSL意思是最大段生命周期(Maximum Segment Lifetime)表明一个包存在于网络上到被丢弃之间的时间。每个IP包有一个TTL(time_to_live),当它减到0时则包被丢弃。每个路由器使TTL减一并且传送该包。当一个程序进入TIME_WAIT状态时,他有2个MSL的时间,这个充许TCP重发最后的ACK,万一最后的ACK丢失了,使得FIN被重新传输。在2MSL等待状态完成后,socket进入CLOSED状态。
  被动关闭:当程序收到一个FIN包从peer,并反馈一个ACK包,于是程序的socket转入CLOSE_WAIT状态。因为peer已经关闭了,所以不能发任何消息了。但程序还可以。要关闭连接,程序自已发送给自已FIN,使程序的TCP socket状态变成LAST_ACK状态,当程序从peer收到ACK包时,程序进入CLOSED状态。

2. Winsock2 API中的相关函数

    先当然是查MSDN,看到winsocks2 API中的相关函数有:closesocket,shutdown,WSASendDisconnect. 我大致说一下,具体详细的资料还请自行查MSDN.

    int closesocket( SOCKET s)的作用是关闭指定的socket,并且回收其所有的资源。
    int shutdown( SOCKET s,  int how)则是禁止在指定的socket s上禁止进行由how指定的操作,但并不对资源进行回收,shutdown之后而closesocket之前s还不能再次connect或者 WSAConnect.
    int WSASendDisconnect( SOCKET s,  LPWSABUF lpOutboundDisconnectData)则和shutdown基本类似,稍有不同的就是WSASendDisconnect函数多了一个lpOutboundDisconnectData参数,可以允许发送“断开数据”(disconnect data).但MSDN上写了“The native implementation of TCP/IP on Windows does not support disconnect data.”,所以一般我们就用shutdown函数就行了。


3. Socket的优雅关闭

在MSDN中对shutdown函数中的Remarks部分有下面一段话,指出了如何进行一次优雅的slcket关闭:

To assure that all data is sent and received on a connected socket before it is closed, an application should use shutdown to close connection before calling closesocket. For example, to initiate a graceful disconnect:

   1. Call WSAAsyncSelect to register for FD_CLOSE notification.
   2. Call shutdown with how=SD_SEND.
   3. When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR.
   4. Call closesocket.

closesocket的行为也是随setsockopt()中参数的不同而有不同的表现,这里影响它的行为的主要就是那个linger结构。


SO_DONTLINGER 若为真,则SO_LINGER选项被禁止。
SO_LINGER 延迟关闭连接 struct linger
上面这两个选项影响close行为
选项 间隔 关闭方式 等待关闭与否
SO_DONTLINGER 不关心 优雅 否
SO_LINGER 零 强制 否
SO_LINGER 非零 优雅 是
若设置了SO_LINGER(亦即 linger结构中的l_onoff域设为非零),并设置了零超时间隔,则closesocket()不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式称为“强制”或“失效”关闭,因为套接口的虚电路立即被复位,且丢失了未发送的数据。在远端的recv()调用将以 WSAECONNRESET出错。
若设置了SO_LINGER并确定了非零的超时间隔,则closesocket()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。请注意如果套接口置为非阻塞且SO_LINGER设为非零超时,则closesocket()调用将以 WSAEWOULDBLOCK错误返回。
若在一个流类套接口上设置了SO_DONTLINGER(也就是说将linger结构的l_onoff 域设为零),则closesocket()调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。请注意,在这种情况下WINDOWS套接口实现将在一段不确定的时间内保留套接口以及其他资源,这对于想用所以套接口的应用程序来说有一定影响。

    所以一般来说,不应该把linger设置为SO_LINGER 并且设置timeout为0,这样的话,当本地主机调用closesocket时将会造成一个“强制”或“失效”的非优雅关闭。可以根据实际情况设置为另外两种情况。
分享到:
评论

相关推荐

    socket server关闭时导致socket client也关闭 的原因及解决办法

    4. **优雅地关闭连接**:Server端在关闭Socket之前,应确保所有的数据已被发送并接收确认,然后通过`shutdown()`函数先关闭发送方向,再关闭接收方向,以告知Client可以安全地关闭连接。 通过以上方法,可以有效地...

    对一个对端已经关闭的socket调用两次write, 第二次将会生成SIGPIPE信号, 该信号默认结束进程.zip

    当我们处理TCP连接时,必须了解如何正确地管理和关闭Socket,因为不恰当的操作可能导致一些异常情况,例如标题中提到的问题:“对一个对端已经关闭的socket调用两次write, 第二次将会生成SIGPIPE信号, 该信号默认...

    很简单的一个socket双向通信小程序源代码

    - 如何优雅地关闭Socket连接,防止资源泄露? 通过这个简单的示例,你可以深入理解Socket通信的基本流程,为构建更复杂的网络应用打下基础。在实践中,你可以尝试修改代码,增加功能,比如添加心跳机制以检测连接...

    一个windows开源socket 库

    在这个场景下,我们讨论的是一个针对Windows平台的开源Socket库,虽然它的知名度可能不高,但因其易用性和实用性而受到开发者的青睐。 首先,让我们深入了解Socket编程的基本概念。Socket是一种编程接口(API),它...

    一个linux下的socket线程池实现

    5. **资源回收**:当线程池不再需要时,需要优雅地关闭所有线程,释放相关资源。 项目的源代码文件"MyLinuxThread"可能包含了上述功能的实现,包括socket的创建和监听、线程池的设计与管理、任务分配机制等。通过...

    基于 Java Socket 的一个通信框架.zip

    此外,异常处理也是关键,确保在网络不稳定或其他错误情况下,程序能够优雅地关闭连接并释放资源。 在"java0323"这个文件中,我们可能会看到以下内容: 1. `ServerSocket`的实例化和`accept()`方法的使用。 2. `...

    java socket 经典版本

    - 在Socket编程中,需要处理各种网络异常,如`IOException`、`SocketException`等,确保程序在遇到问题时能够优雅地关闭连接并释放资源。 4. **关闭连接**: - 当通信完成后,必须关闭Socket和ServerSocket以释放...

    Socket编程实验报告.docx

    同时,它还强调了异常处理的重要性,当出现错误时,程序能够优雅地关闭资源,避免资源泄漏。 在实际应用中,Socket编程广泛应用于各种网络服务,如Web服务器、FTP服务器、邮件服务器等,它是实现网络应用程序间通信...

    android socket 编程实例

    同时,需要注意处理异常,确保在出现错误时能优雅地关闭Socket和流。 在实际开发中,我们通常会封装一个Socket通信类,提供发送和接收数据的方法,以便在应用的其他部分轻松使用。此外,考虑到网络连接可能不稳定,...

    【Android】socket client发送一个字符串

    本文将详细讲解如何在Android客户端通过Socket发送一个字符串。 首先,我们需要了解Socket的基本概念。Socket是网络编程中的一个接口,它允许两个程序通过网络连接交换数据。在Android中,我们可以使用Java的Socket...

    SSocket 实例代码 demo 是初学者不可多得的Socket编程学习资料

    3. **异常处理**:熟悉Socket编程中的常见异常,如IOException,以及如何优雅地处理这些异常。 4. **线程处理**:在服务器端,通常需要为每个客户端连接创建一个新的线程,以便同时处理多个客户端请求。 5. **关闭...

    C# socket 多线程实例

    "C# socket 多线程实例"着重于利用.NET框架提供的Socket类来创建一个可以处理多个并发连接的服务器,并通过多线程来提高性能和响应速度。 Socket是网络通信的基础,它提供了低级别的接口,允许应用程序进行数据传输...

    C# Socket通讯DEMO

    - **错误处理**:确保在出现异常时,如网络中断,能够优雅地关闭Socket连接并提示用户。 6. **项目结构**: “Socket-master”可能包含服务端(Server)和客户端(Client)两个子项目,每个项目有自己的解决方案...

    C#Socket简单聊天

    为了使程序更加健壮,我们还需要考虑错误处理和异常捕获,确保在出现网络问题或用户操作不当时能够优雅地关闭连接并给出提示。此外,考虑到多用户环境,服务端可能需要维护一个客户端列表,用以管理多个并发的连接。...

    实战Linux Socket编程源码

    例如,客户端断开连接时,服务器需要优雅地关闭对应的Socket;为了避免内存泄漏,需要正确释放分配的资源;为了提高性能,可能需要调整缓冲区大小、优化数据打包和解包等。 总之,"实战Linux Socket编程源码"提供了...

    SocketClient.zip

    SocketClient.zip是一个包含Socket客户端实现的压缩包,其核心功能是提供支持断线重连的能力。在进行网络Socket通信时,由于网络环境的不稳定性,可能会导致连接中断,此时Socket客户端能够自动尝试重新建立连接,...

    Socket 网络编程例子程序

    因此,编写健壮的Socket程序需要良好的异常处理机制,以确保程序在遇到问题时能够恢复或优雅地关闭。 8. **数据编码与解码**:在传输过程中,数据通常需要进行编码,如ASCII、UTF-8等。发送和接收数据时,理解并...

    socket通信文件传输

    Socket,也称为“套接字”,是网络通信中的一个抽象概念,它代表了两台机器之间的一个连接端点。在TCP/IP模型中,Socket接口提供了应用层与传输层之间的交互,允许应用程序发送和接收数据。 2. **TCP/IP协议**: ...

    封装的非常完善的socket类,支持服务器客户端多个连接

    在给定的标题和描述中,我们可以看到这里提供了一个已经封装得非常完善的Socket类,它支持服务器与客户端的多个连接,大大简化了开发人员的工作,使其能更方便地进行网络通信。 首先,让我们了解一下Socket的基本...

    winformSocket异步通信

    1. **创建Socket对象**:使用`new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)`创建一个TCP Socket对象。 2. **设置异步事件处理委托**:为了处理Socket的异步操作,我们需要为...

Global site tag (gtag.js) - Google Analytics