网络编程实战
盛延敏
前大众点评云平台首席架构师
44207 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
网络编程实战
15
15
1.0x
00:00/00:00
登录|注册

11 | 优雅地关闭还是粗暴地关闭 ?

默认处理 vs 自定义函数处理的区别
调用exit(0)完成FIN报文发送的原因
调用exit(0)完成FIN报文发送
SIGPIPE信号处理
输入"close" vs "shutdown"
select多路复用
关闭连接的方式比较
与close函数的差别
关闭读和写两个方向
关闭连接的写方向
关闭连接的读方向
关闭两个方向的数据流
套接字引用计数
关闭套接字
优雅关闭 vs 粗暴关闭
数据流方向
半连接状态
TIME_WAIT状态
四次挥手
三次握手
思考题
服务器端程序
客户端程序
close vs shutdown
shutdown函数
close函数
TCP连接关闭

该思维导图由 AI 生成,仅供参考

你好,我是盛延敏,这里是网络编程实战第 11 讲,欢迎回来。
上一讲我们讲到了 TCP 的四次挥手,其中发起连接关闭的一方会有一段时间处于 TIME_WAIT 状态。那么究竟如何来发起连接关闭呢?这一讲我们就来讨论一下。
我们知道,一个 TCP 连接需要经过三次握手进入数据传输阶段,最后来到连接关闭阶段。在最后的连接关闭阶段,我们需要重点关注的是“半连接”状态。
因为 TCP 是双向的,这里说的方向,指的是数据流的写入 - 读出的方向。
比如客户端到服务器端的方向,指的是客户端通过套接字接口,向服务器端发送 TCP 报文;而服务器端到客户端方向则是另一个传输方向。在绝大多数情况下,TCP 连接都是先关闭一个方向,此时另外一个方向还是可以正常进行数据传输。
举个例子,客户端主动发起连接的中断,将自己到服务器端的数据流方向关闭,此时,客户端不再往服务器端写入数据,服务器端读完客户端数据后就不会再有新的报文到达。但这并不意味着,TCP 连接已经完全关闭,很有可能的是,服务器端正在对客户端的最后报文进行处理,比如去访问数据库,存入一些数据;或者是计算出某个客户端需要的值,当完成这些操作之后,服务器端把结果通过套接字写给客户端,我们说这个套接字的状态此时是“半关闭”的。最后,服务器端才有条不紊地关闭剩下的半个连接,结束这一段 TCP 连接的使命。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了TCP连接关闭的两种方式:使用close函数和shutdown函数。close函数会关闭套接字的引用计数并释放所有连接资源,同时关闭TCP连接的两个方向的数据流;而shutdown函数可以选择关闭连接的读、写或两个方向,不会释放套接字和资源,并总是发送FIN结束报文通知对端。文章通过实验展示了使用close和shutdown函数的差别,并展示了如何在实际程序中应用它们。通过对客户端和服务器端程序的详细解释,读者可以了解两种关闭方式的差别和适用场景。此外,文章还提到了对SIGPIPE信号的处理,以避免程序意外退出。总之,本文通过实例和时序图清晰地展示了TCP连接关闭的两种方式及其影响,为读者提供了清晰的技术指导。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《网络编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(77)

  • 最新
  • 精选
  • 卫江
    问题一,为什么调用exit以后不需要调用close,shutdown?因为在调用exit之后进程会退出,而进程相关的所有的资源,文件,内存,信号等内核分配的资源都会被释放,在linux中,一切皆文件,本身socket就是一种文件类型,内核会为每一个打开的文件创建file结构并维护指向改结构的引用计数,每一个进程结构中都会维护本进程打开的文件数组,数组下标就是fd,内容就指向上面的file结构,close本身就可以用来操作所有的文件,做的事就是,删除本进程打开的文件数组中指定的fd项,并把指向的file结构中的引用计数减一,等引用计数为0的时候,就会调用内部包含的文件操作close,针对于socket,它内部的实现应该就是调用shutdown,只是参数是关闭读写端,从而比较粗暴的关闭连接。 第二个问题,信号的处理有三种,默认处理,忽略处理,自定义处理。默认处理就是采用系统自定义的操作,大部分信号的默认处理都是杀死进程,忽略处理就是当做什么都没有发生。

    作者回复: 赞赞赞。

    2019-09-03
    7
    125
  • zhchnchn
    请问老师一个问题,像FIN,ACK等报文并不属于“数据”是么?比如对于4次挥手中,发起关闭的客户端在发送FIN报文后,表明客户端不再发送“数据”了(可以读数据),之后在服务端也发送FIN报文后,客户端还是会发送一个ACK报文给服务端。这里的最后一个ACK报文,并不属于“数据”是吗?T或者CP中这些所有的控制报文包都不属于所谓的“数据”吗?

    作者回复: 这是控制报文,是脱离应用程序掌握之外的控制协议部分,层这个层面来说,他们不被认为是"应用层数据"。

    2019-09-03
    2
    32
  • Guchen
    老师我这个理解有问题么? 客户端调用close并发送了FIN包,服务端接收到FIN包会将连接状态设置为对端已关闭写端,服务端在向客户端回送FIN包之前可以向对端发送数据也不可不发送,实例程序就是发送了数据,第一次发送数据对端会返回个RST包(因为客户端close已经关闭了读端),服务端调用read会返回-1,设置errno,此时服务端了解到客户端也不会再读数据了,如果服务端还是强行再次向客户端发送数据包,调用write后,协议栈会发现用户进程向一个没有读用户的管道做写操作,那么会触发SIGPIPE信号执行默认操作关闭用户进程。

    作者回复: 正解~

    2020-10-21
    4
    17
  • skye
    那请问老师,什么情况下用close,什么情况下用shutdown?谢谢!

    作者回复: 你想彻底关闭双向连接的时候用close,你想只关闭自己这端到对端的连接时用shutdown。

    2019-12-29
    11
  • W.jyao
    SUG_IGN是忽略信号吧,老师是不是代码有问题啊,SIG_DFL才是默认处理,示例中那样写不是应该是忽略了SIGPIPE信号么。

    作者回复: 嗯,你试一下改改是不是可以的,我应该是写错了。

    2019-08-27
    3
    9
  • 传说中的成大大
    然后又引申了fin包和read返回0是怎样的关系呢?

    作者回复: 读到FIN包在read看来就是返回0.

    2019-08-27
    8
  • 忆水寒
    close关闭比较粗暴,如果想要优雅的关闭,等处理完数据再关闭可以使用shutdown设置参数。 实际上在tcp协议中有个参数so_linger也可以设置比较优雅(规定时间处理缓冲区的字节,超时则清空缓冲区)的关闭tcp的socket。

    作者回复: 学习了,后面应该会讲到SO_LINGER。

    2020-03-08
    7
  • 传说中的成大大
    今天我也写了代码测试上面的例子同时也想起了网上一句话 close是关闭掉socket 并且回收了socket相关资源,而shutdown一般只是关闭连接并不会关闭socket 这也是为啥调用close服务器端在进行写数据的时候会触发sigpipe信号,而shutdown却不会触发,那么调用shutdown关闭的套接字怎么回收呢?是由内核回收还是? 服务器端和客户端又是怎样回收的呢?

    作者回复: 我理解还是内核会回收的,只不过是等待双向连接都关闭掉才会回收。

    2019-08-28
    2
    4
  • W.jyao
    老师,调用shutdown不会释放套接字资源,那么应该怎么处理呢

    作者回复: 不会立即释放,最终还是会被系统内核回收的。

    2019-08-27
    4
  • Sun
    close 关闭两个方向的数据流时。输入方向,系统内核会将该套接字设置为不可读,任何读操作都会返回异常。在输出方向,系统内核尝试将发送缓冲区的数据发送给对端,那对端已经不可读了,这些数据该如何处理?

    作者回复: 有顺序的,系统会在所有待发送的有效数据之后,插入一个EOF标识发送给对端,对端也是在处理完所有发送给自己的有效数据之后,才会读到EOF标识。换句话说,这是有一个过程的,并不是瞬间就达到的。

    2020-04-25
    2
    3
收起评论
显示
设置
留言
77
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部