在《三次握手与Socket API》中咱们详细讲解了三次握手以及与之相关的API,三次握手是TCP协议的初始阶段,用来创建双方通讯链接,显然有创建链接就有断开链接,那么TCP是如何断开链接的呢?程序员
TCP协议创建链接须要进行三次信息交互,断开链接时却须要四次信息交互,这四次信息交互被形象的称为四次挥手,那么TCP在断开链接时为何须要奇怪的四次挥手而不是三次挥手呢?要想回答这个问题咱们必须对TCP协议有进一步的理解。编程
生活中总会有这两类人,一类话多,一类话少,话少的那个言简意赅很快就无话可说了,话多的那个口若悬河没完没了,所以就会有这样的情形:服务器
A: 今每天气这不错啊 A: 今天饭也好吃 A: 是吧 是的 :B 我说完了 :B A: 我还没说完呢 A: 明天就周五啦 A: 开心 A: blablabla A: 我也说完了
当这两类人在聊天时就会出现B说完但A没说完的状况,这时B再也不说话可是能够继续听A说,当A也说完后整个聊天过程才算结束。微信
TCP通讯过程和人聊天又有多大区别呢?网络
有话多话少的人固然也会有数据多数据少的客户端以及服务器。socket
在TCP通讯中一方表示“我说完了”其实是经过向对方发送一条带有FIN标识的消息来实现的,当一方收到FIN信息时就知道接下来对方就不会再发送数据了,这在TCP协议中被称为半关闭,half-close。函数
TCP为何要支持半关闭呢?为何不是一方说完你们都闭嘴呢?spa
原来TCP通讯和两我的聊天是同样的,你在说话的同时也在听,也就是说你能够同时收发信息,这就是所谓的全双工通讯,在这种通讯方式下你说完了不表明对方也说完了,所以只有双方都说完了链接才能彻底关闭。操作系统
TCP也是全双工通讯,TCP规定通讯的任意一方均可以向对方发送FIN信息(表示我说完了),但这也仅仅表示一方没什么要发送的了,但这并不影响对方继续发送数据(对方还没发送完数据)。3d
这就是为何TCP支持半关闭的缘由,半关闭的本质就是TCP通讯中一方已经没什么数据要发送了,虽然没有数据要发送但还能够继续接收数据
理解了前几节接下来就简单啦,假设有一个话少的客户端和一个话多的服务器端就会有以下情形:
从图中咱们能够看出虽然客户端发送了FIN信息但此时服务器端还有数据要发送,所以服务器端没有理会客户端发送的FIN而是继续发送数据直到服务器端也发送完,此时服务器端发送FIN表示数据发送完毕,客户端接收到消息后进行ACK回复,这时TCP链接才真正断开。
不过值得注意的是,做为程序员在网络编程中咱们几乎不会遇到上述情形,一般客户端向服务器端发送FIN后服务器端就不会再向客户端继续发送数据了,通常状况下TCP通讯的整个过程都是客户端来主导的,客户端主动发起链接,获取到想要的信息后主动断开链接,服务器端只是被动同客户端创建连接,客户端想要什么服务器端通过处理后就返回给客户端什么,当客户端不想再聊天时服务器端也不会还在口若悬河,总而言之,客户端与服务器就比如用户和客服同样,整个过程都是用户来主导的,客服只是被动的来回答问题,当用户没什么问题后没有哪一个客服还会继续和用户聊下去,固然客服让用户给好评除外,放心,服务器端是不须要客户端给好评的 :) ,所以咱们一般看到的这样的情形:
有的同窗可能会想,为何B发送的ACK和FIN不能和三次握手同样合并成一次呢?就像这样:
若是只有三次挥手那么TCP就没有办法支持半关闭了,三次挥手实际是在说“若是有一方闭嘴那么咱们都闭嘴”,虽然做为程序员咱们在网络编程时遇到的都是这种情形,可是从TCP协议层面来讲应该支持半关闭,也就是支持通讯双方中一个话多一个话少的情形。
如今你应该明白为何要四次挥手而不能是简单的三次了吧。
四次挥手与close
和三次握手同样,四次挥手也有与之相对应的API,这样的API有两个,一个是咱们经常使用的close,另外一个是shutdown。
close是咱们最常使用的一个,既然close是最经常使用的,那么close也就用在“一方闭嘴你们都闭嘴”的情形,如图所示:
咱们已经知道四次挥手一般是由客户端来发起的,当客户端执行close函数后会向服务器端发出FIN消息,服务器端操做系统接收到该信息后向服务器进程发出EOF(end of file),这时服务器不管调用send仍是recv都会失败,此时服务器端认为客户端已经关闭了链接,所以调用close函数关闭同客户端的链接,当客户端接收到FIN信息后进行ACK回复确认,整个四次挥手的过程完毕。
四次挥手与shutdown:半关闭
客户端和服务器使用close来完成四次挥手是最多见的过程,即“一方闭嘴你们都闭嘴”,咱们知道做为全双工通讯协议的TCP还须要支持半关闭,也就是说一方说完但另外一方还在说的场景,这时先说完的就只能听了,做为程序员咱们须要知道几乎没有什么应用场景要用到TCP提供的半关闭能力。
当客户端调用close后若是服务器端没有理会而是继续向客户端发数据,那么此时客户端是接收不到的,固然这就是客户端调用close函数的目的。
而若是客户端表示:“我没什么要说的了,因此要向服务器发送FIN,可是我还想听服务器啰嗦一下子直到对方也说完”该怎么办呢?这时客户端就不能调用close了而是应该调用socket提供的另外一个API,也就是shutdown,典型的场景如图所示:
虽然客户端调用shutdown向服务器端发送了FIN表示本身说完了,可是服务器端仍是能够继续向客户端发送任意多的数据,而客户端依然能够接收到数据,直到服务器端也发送FIN消息客户端回复ACK确认后链接才算是真正关闭。
如今你应该明白如何使用shutdown利用TCP的半关闭能力了吧。
本文是继《三次握手与Socket API》的第二篇,讲述了四次挥手的过程以及为何须要四次挥手,之因此须要四次挥手是由于TCP协议须要提供一种被称为半关闭的能力,可是不多有应用场景须要依赖该能力。做为程序员咱们须要知道大部分状况下使用close就能够完成四次挥手,可是若是须要依赖TCP提供的半关闭能力那么须要使用另外一个API,也就是shutdown。
若是你喜欢这一系列的文章,也欢迎关注个人微信公共帐号,码农的荒岛求生,获取更多内容。
计算机内功决定程序员职业生涯高度