socket编程-优雅的断开连接shutdown

摘要:
调用close()/closesocket()函数意味着完全断开连接,即不能发送数据也不能接收数据,这种“生硬”的方式有时候会显得不太“优雅”。调用close()/closesocket()关闭套接字时,或调用shutdown()关闭输出流时,都会向对方发送FIN包。默认情况下,close()/closesocket()会立即向网络中发送FIN包,不管输出缓冲区中是否还有数据,而shutdown()会等输出缓冲区中的数据传输完毕再发送FIN包。

调用 close()/closesocket() 函数意味着完全断开连接,即不能发送数据也不能接收数据,这种“生硬”的方式有时候会显得不太“优雅”。
在这里插入图片描述
上图演示了两台正在进行双向通信的主机。主机A发送完数据后,单方面调用 close()/closesocket() 断开连接,之后主机A、B都不能再接受对方传输的数据。实际上,是完全无法调用与数据收发有关的函数。

一般情况下这不会有问题,但有些特殊时刻,需要只断开一条数据传输通道,而保留另一条。
使用 shutdown() 函数可以达到这个目的,它的原型为:

int shutdown(int sock, int howto); //Linux
int shutdown(SOCKET s, int howto); //Windows

sock 为需要断开的套接字,howto 为断开方式。

howto 在 Linux 下有以下取值:

  • SHUT_RD:断开输入流。套接字无法接收数据(即使输入缓冲区收到数据也被抹去),无法调用输入相关函数。
  • SHUT_WR:断开输出流。套接字无法发送数据,但如果输出缓冲区中还有未传输的数据,则将传递到目标主机。
  • SHUT_RDWR:同时断开 I/O 流。相当于分两次调用 shutdown(),其中一次以 SHUT_RD 为参数,另一次以 SHUT_WR 为参数。

howto 在 Windows 下有以下取值:

  • SD_RECEIVE:关闭接收操作,也就是断开输入流。
  • SD_SEND:关闭发送操作,也就是断开输出流。
  • SD_BOTH:同时关闭接收和发送操作。

至于什么时候需要调用 shutdown() 函数,下节我们会以文件传输为例进行讲解。

close()/closesocket()和shutdown()的区别

确切地说,close() / closesocket() 用来关闭套接字,将套接字描述符(或句柄)从内存清除,之后再也不能使用该套接字,与C语言中的 fclose() 类似。应用程序关闭套接字后,与该套接字相关的连接和缓存也失去了意义,TCP协议会自动触发关闭连接的操作。shutdown() 用来关闭连接,而不是套接字,不管调用多少次 shutdown(),套接字依然存在,直到调用 close() / closesocket() 将套接字从内存清除。
调用 close()/closesocket() 关闭套接字时,或调用 shutdown() 关闭输出流时,都会向对方发送 FIN 包。FIN 包表示数据传输完毕,计算机收到 FIN 包就知道不会再有数据传送过来了。
默认情况下,close()/closesocket() 会立即向网络中发送FIN包,不管输出缓冲区中是否还有数据,而shutdown() 会等输出缓冲区中的数据传输完毕再发送FIN包。也就意味着,调用 close()/closesocket() 将丢失输出缓冲区中的数据,而调用 shutdown() 不会。

免责声明:文章转载自《socket编程-优雅的断开连接shutdown》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转】CUDA程序优化要点ubuntu 修改用户名和密码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

使用shutdown命令实现局域网内远程关机、重启整蛊他人

用法: shutdown [/i | /l | /s | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/soft] [/f]    [/m \computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]     没有参数   显示帮助。这与键入 /? 是一样的。    /? ...

FTPClient

using System;using System.Net;using System.IO;using System.Text;using System.Net.Sockets;using System.Threading; public class FTPClient{public static object obj = new object(); #r...

面试题--赵银科技

1.pubilc A{ public void test(){} }  public B extends A{ protected void test(){} } 这样有问题吗?为什么?  错, 2.public A{ public long test(){} }  public B extends A{ public int test(){} } 这样有...

Python之路(第三十篇) 网络编程:socket、tcp/ip协议

一、客户端/服务器架构1.硬件C/S架构(打印机) 打印机作为一个服务端,电脑连接打印机进行打印 2.软件C/S架构   互联网中处处是C/S架构   如谷歌网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种)   腾讯作为服务端为你提供视频,你得下个腾讯视频客户端才能看它的视频) C/S架构与socket的关系: 我们学习socket就是为...

Linux下高并发socket最大连接数各种限制的调优

1、修改用户进程可打开文件数限制  在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。可使用ulimit命令查看系统允许当前用户进程打开的文件数限制: [s...

python+mitmproxy抓包过滤+redis消息订阅+websocket实时消息发送,日志实时输出到web界面

本实例实现需求 在游戏SDK测试中,经常需要测试游戏中SDK的埋点日志是否接入正确。本实例通过抓包(客户端http/https 请求)来判定埋点日志是是否接入正确。 实现细节:使用django项目,后端采用python mitmdump 扩展脚本“log_handler.py”实时抓取与过滤4399SDK 客户端日志,将数据处理成约定需要的格式,保存和发布...