网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
6034 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 学好网络编程,需要掌握哪些核心问题?
免费
第一模块:基础篇 (9讲)
01 | 追古溯源:TCP/IP和Linux是如何改变世界的?
02 | 网络编程模型:认识客户端-服务器网络模型的基本概念
03丨套接字和地址:像电话和电话号码一样理解它们
04 | TCP三次握手:怎么使用套接字格式建立连接?
05 | 使用套接字进行读写:开始交流吧
06 | 嗨,别忘了UDP这个小兄弟
07 | What? 还有本地套接字?
08 | 工欲善其事必先利其器:学会使用各种工具
09丨答疑篇:学习网络编程前,需要准备哪些东西?
第二模块:提高篇 (10讲)
10 | TIME_WAIT:隐藏在细节下的魔鬼
11 | 优雅地关闭还是粗暴地关闭 ?
12 | 连接无效:使用Keep-Alive还是应用心跳来检测?
13 | 小数据包应对之策:理解TCP协议中的动态数据传输
14丨UDP也可以是“已连接”?
15 | 怎么老是出现“地址已经被使用”?
16 | 如何理解TCP的“流”?
17 | TCP并不总是“可靠”的?
18 | 防人之心不可无:检查数据的有效性
19丨提高篇答疑:如何理解TCP四次挥手?
期中复习周 (2讲)
期中大作业丨动手编写一个自己的程序吧!
免费
期中大作业丨题目以及解答剖析
免费
第三模块:性能篇 (12讲)
20 | 大名⿍⿍的select:看我如何同时感知多个I/O事件
21 | poll:另一种I/O多路复用
22 | 非阻塞I/O:提升性能的加速器
23 | Linux利器:epoll的前世今生
24 | C10K问题:高并发模型设计
25 | 使用阻塞I/O和进程模型:最传统的方式
26 | 使用阻塞I/O和线程模型:换一种轻量的方式
27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
28 | I/O多路复用进阶:子线程使用poll处理连接I/O事件
29 | 渐入佳境:使用epoll和多线程模型
30 | 真正的大杀器:异步I/O探索
31丨性能篇答疑:epoll源码深度剖析
第四模块:实战篇 (4讲)
32 | 自己动手写高性能HTTP服务器(一):设计和思路
33 | 自己动手写高性能HTTP服务器(二):I/O模型和多线程模型实现
34 | 自己动手写高性能HTTP服务器(三):TCP字节流处理和HTTP协议实现
35 | 答疑:编写高性能网络编程框架时,都需要注意哪些问题?
结束语 (1讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

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

盛延敏 2019-08-26
你好,我是盛延敏,这里是网络编程实战第 11 讲,欢迎回来。
上一讲我们讲到了 TCP 的四次挥手,其中发起连接关闭的一方会有一段时间处于 TIME_WAIT 状态。那么究竟如何来发起连接关闭呢?这一讲我们就来讨论一下。
我们知道,一个 TCP 连接需要经过三次握手进入数据传输阶段,最后来到连接关闭阶段。在最后的连接关闭阶段,我们需要重点关注的是“半连接”状态。
因为 TCP 是双向的,这里说的方向,指的是数据流的写入 - 读出的方向。
比如客户端到服务器端的方向,指的是客户端通过套接字接口,向服务器端发送 TCP 报文;而服务器端到客户端方向则是另一个传输方向。在绝大数情况下,TCP 连接都是先关闭一个方向,此时另外一个方向还是可以正常进行数据传输。
举个例子,客户端主动发起连接的中断,将自己到服务器端的数据流方向关闭,此时,客户端不再往服务器端写入数据,服务器端读完客户端数据后就不会再有新的报文到达。但这并不意味着,TCP 连接已经完全关闭,很有可能的是,服务器端正在对客户端的最后报文进行处理,比如去访问数据库,存入一些数据;或者是计算出某个客户端需要的值,当完成这些操作之后,服务器端把结果通过套接字写给客户端,我们说这个套接字的状态此时是“半关闭”的。最后,服务器端才有条不紊地关闭剩下的半个连接,结束这一段 TCP 连接的使命。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(39)

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

    作者回复: 赞赞赞。

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

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

    2019-09-03
    6
  • 传说中的成大大
    思考题
    1. 调用exit(0) 是系统内核自动回收了一切资源,关闭了一切相关的文件
    2. SIG_IGN是忽略该信号 如果是采用SIG_DEF默认处理方式则是由系统进行一些处理,而自定义函数的话 是捕捉到该信号并进入回调 自己处理相关事宜
    2019-08-27
    3
  • 传说中的成大大
    然后又引申了fin包和read返回0是怎样的关系呢?

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

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

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

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

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

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

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

    2019-08-27
    1
  • 胡波 allenhu
    老师你好, 上面的例子中有两个地方不是很清楚:
    (1) close: client调用close后, 不是会马上关闭两个方向的连接吗, 那为啥"Hi, data1"还能被收到并显示?
    (2) shutdown: client调用shutdown只是关闭写方向的连接, 是不是client不能发了只能收?那为啥server能读到EOF并发送"FIN"给client?

    作者回复: 1.那是之前发送的;
    2.那是shutdown的结果,shutdown之后,就是往队列里扔了一个FIN报文,这个发送队列还是要被发送完成的。

    2019-08-26
    1
  • Geek_68d3d2
    这个程序服务端好像没有发送FIN包就直接退出了吧 我把服务端read返回0的情况下error注掉,服务端已在再向客户端发送Hi。

    作者回复: 哪个程序?是close的还是shutdown的?如果把read返回0注释掉,说明是对端已经发起结束,这个时候是服务端是需要正常退出的,不明白注释的想法是?

    2019-12-05
  • godtrue
    看完这篇,感觉自己跟不上了😁,有好多细节都是第一次听说,不过也有一点收获,所以,要坚持。
    这节,感觉印证了我上节的猜想,老师对于四次挥手并没有像建立连接时的三次握手那么详细,我也没跳读的。

    TCP连接的三次握手机制主要是为了解决,怎么确保信道安全可靠的问题,为了确认双方的收发能力都OK,需要四次通信,不过其中两次的收发可以合并,所以,三次握手就行了

    TCP断链的四次挥手机制,主要为了解决双方的收发数据都能正常结束,才这么设计的,因为TCP连接的两个特点,一是传输的是字节流,二是通信方式为双工通信。所以,一端想关闭连接,就需要不再继续写且发送一个FIN,另一端需要处理完对应的读,然后发一个ACK进行响应。
    我有个疑问,四次挥手的其中两次不能像三次握手一样合并为一次通信嘛?是因为处理读可能存在慢动作吗?怕耽误ACK的响应时间嘛?

    作者回复: 因为有双向连接的问题,所以一般不会合并。

    2019-11-23
    1
  • 美美
    实际测试时把shutdown 里的参数设置成了0,但是抓包客户端也发FIN包了,SHUT_RD(0)老师讲的不会发FIN包呢

    作者回复: 有点误解哦,FIN是会发的,只是一个方向的连接会被关闭,另一个方向正常的。

    2019-11-22
  • 破晓^_^
    本文中例子,客户端发送data1和data2后无返回是因为sleep了吗?还有实验的时候是不是close和shutdown的输入必须在5s内完成,否则服务器端不休眠了直接把数据发到客户端了。

    作者回复: 第一个问题,是的,这个是因为close调用之后sleep了;

    第二个问题,应该在10秒之内就可以了,这个例子是为了展示close和shutdown的区别。

    2019-10-29
  • 我的名字
    代码移植到win10上,select总是返回-1, WSAGetLastError()为10038。老师,能说一下,如果是win10的话,使用哪种方式能实现与本文相同的功能?

    作者回复: 建议使用虚拟机安装一个ubutnu的Linux,在Linux下实验。

    2019-10-16
    1
  • 苦行僧
    老师 请问FTP连接一半 服务端返回421是什么原因导致的 查了好久

    作者回复: 一个直观的解释就是太多ftp连接了,我google了一下,似乎还有被动连接和主动连接模式的问题,建议你看一下。

    2019-09-21
  • 愚人
    如果client端在close之后没有sleep直接exit退出,也就是client发送完FIN后不再等待server的FIN(也不会回应FIN ACK), server端在LAST ACK状态下以什么形式退出?

    作者回复: 我认为还是会回到CLOSED状态,在LAST ACK状态下的等待ACK等不到,应该有容错处理逻辑。

    2019-09-16
  • 星辰
    初学了c 想把基础知识补一下
    看到linux内核 第三版 p32 信号与进程间的通信
    想起了老师的课后提问
    原来这个SIG_是内核和进程间的通信

    作者回复: 嗯

    2019-09-14
  • Geek_ca852b
    在CLion中如何运行啊?

    作者回复: 直接从菜单中选择“Run-Run",然后找到想跑的应用程序名,就可以了。

    2019-09-13
  • Leon📷
    _exit也可以的,就是更粗暴的一些
    2019-09-12
  • Geek_Claire
    文中在close之后,输入方向不可读等输入方向、不可读指的都是那个socket,不可读是close方不可读取对方,还是对方不可读close方,这里感觉有点绕和晕

    作者回复: 看一下后面的那种序列图,会好很多。

    2019-09-11
  • Geek_Claire
    客户端close调用后 ,服务端对FIN进行ACK后,只能将缓存中的数据发送完毕后发送FIN,如果再调用send发送其他数据 就会触发SIGPIPE 是这样吗?

    作者回复: 要send两次,一次会拿到RST信号,第二次就会SIGPIPE。不过,不同版本的UNIX实现是不同的,稍后你会看到,Linux下其实并不会这样。

    2019-09-06
收起评论
39
返回
顶部