前言
记得初学C++,老师讲解到TCP协议。我那时候听的云里雾里,听着听着就糊涂了。为啥TCP的报文格式是一个方块图(就是网络上很常见的那种),不是说传输都是二进制吗?为啥建立连接时候发送的是SYN,seq=x。是客户端直接发送一个字符串"SYN"给对方吗?
这些简单的概念听着听着都混了,更别说后面讲到三次握手,四次断开了。总之,当时学完的感受就是,TCP好难啊,网络编程太难了,学不会,感觉自己干不了编程。
当时心态都奔溃了,此后多年,就一直认为自己不适合这行。可见当时没学会对我造成了多大的影响。这两年机缘巧合,又重新接触到了TCP,在查阅大量资料、不断验证后。突然就理解了TCP协议,发现它也没有当时那么难。也许是当时老师讲的不行,也许是当时的自己知识储备不够。总之,现在信心突然增加了。虽然理解的还不够全面,但面试时候提TCP,我肯定给你说出个123来。
这也是我为啥要出一版TCP专栏的原因,希望后面有想学习TCP的同学,能少走一些弯路,不会觉得它有那么难。能有效帮助初学者,我就心满意足了。
什么是TCP
官方的定义是:TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。
现在来看,这段话高度概括了TCP的核心思想。如果不了解TCP的底层实现机制,是不可能对这段话有深刻印象的。
什么是面向连接?
协议的本质是通讯、是对话、是消息传递。而通讯的方式有很多种,比如用喇叭广播新闻:我不需要你们回复,我也不管你们是否听到了。我只管广播宣布。比如写信,又不能像广播一样给所有人写,要知道对方地址才行。如果期待对方回信,也要把自己的地址告诉他。再比如,打电话,光知道对方号码还不行,还要对方点击接听按钮。否则就打不通。
上面三种方式,哪种更像是面向连接呢?答案很显然,是打电话。所以面向连接,指的就是通讯双方要提前约定好,两边都准备好才能通讯,任何一方还没好,是不能通讯的。是个一对一的过程。代码逻辑层面如何实现呢?就是问答。A想和B通话。A:b你准备好了吗。B:还没有,等等。过了一会。B:我好了,你好了吗。A:我肯定好了啊,等你半天了。好,那开始互发消息吧。
什么是可靠的?
可靠是针对消息而言。比如我给对方发一份信,我怎么才能知道对方是否收到呢?答案对方给我回个信。你回信了,说明你肯定收到了。你没回信,要不然信路上丢了,没投递成功。要不然就是你回信了,但回信在路上也丢了。我重新发一份新的就行。你收到这份信后,不管之前有没有收到过其他的,直接给我回复就行了。我就知道你确实收到了。
如果一直不回复怎么办,那就可以认为中间道路坏了,暂时先不通信,等路修好再说。
所以可靠是通过应答机制实现的。这也是TCP区别udp的核心所在。
什么是基于字节流?
上层应用,无论发送文本、还是二进制消息。无论是1M,还是1G。底层都会存到内核的缓冲区上。而内核是不判断消息哪里是开始,哪里是结束。它就把缓冲区中的数据看成一个个连续的字节。然后给这些字节编个序号。这次发送10个字节,序号范围1-10。下次发送20个字节。序号范围11-30。序号和应答相互配合,也是TCP核心概念之一。
什么是传输层协议?
简化版的网络模型,是物理链路层、网络层、传输层、应用层。每层都干自己的事情,相互解耦,提高效率。
比如链路层,负责把二进制数据转为电信号。这里面只需要知道主机mac地址就行。网络层,负责把数据包从这台机器发给另外一台机器。只需要知道对方IP就行。至于这个数据包给哪个程序,我不管,那是传输层事。为了知道数据包是哪个程序的,必须知道端口。所以传输层协议只携带端口信息就行。
IP协议,就属于网络层协议。而TCP就属于传输层协议。