预备知识
TCP提供可靠连接的原理:
- 每个TCP包都有一个序列号,接收方通过该序列号将响应数据包正确排序;也通过该序列号发现传输序列中丢失的数据包,并请求重传。
- TCP并不使用顺序的整数作为数据包的序列号,而是通过一个计数器来记录发送的字节数。以字节数+上一个数据包的序列号的方式生成序列号。这样,需要重传的时候,只要把数据流用另一种方式分割成新的数据包,就可以让接收方重新接收正确的数据包流。
- TCP不通过锁步(等待上一个接受被确认以后才发送下一个数据包)的方式进行通信。而是一次发送多个数据包。在某一时刻,发送方希望同时传输的数据量叫做TCP窗口。
- 接收方的TCP实现可以通过控制发送方的窗口大小来减缓或暂停连接。这叫做流量控制。
- 最后,如果TCP认为数据包被丢弃了,它会减少每秒发送的数据量,并假定网络正在变得拥堵。
大名鼎鼎的三次握手,四次挥手:
(这个是网图,我不小心加了水印,不知道怎么去掉)下图是TCP建立连接的过程。
SYN:“我想进行通信,这是数据包和初始序列号。”
SYN-ACK:“好的,这是我向你发送数据包的初始序列号。”
ACK:“好的。”
结束过程,在图里看起来也很简单:
FIN:“我们结束吧。”
ACK:“好的。”
FIN:“我们结束吧。”
ACK:“好的。”
(有些情况下,其实只需要三次挥手,即FIN,ACK-FIN,ACK)
但是,我初学到这里的时候有个疑惑,以上图为例:
服务端最后为什么接收客户端的ACK呢?这不是已经结束了吗,他怎么接受这个ACK的呢?
抛开TCP,挂电话的时候,我只需要挂掉就行了,并不是我挂了电话,然后等对方也点击了挂电话的按钮,我们才能结束通话这个机制,逻辑上是有问题的啊,这样的话,岂不是我们永远也不能结束通话?一直要相互确认?
解答在后面。
TCP套接字
和UDP的套接字的概念是一样的,前一篇文章讲过,这里就不赘述了。
但是,TCP套接字有一个特殊的机制:
这个机制可以解决上面的问题。(客户端的TCP套接字和UDP没什么差别)
完整的服务端TCP套接字其实是两个套接字:
被动套接字(监听套接字)+ 主动套接字(连接套接字)
监听套接字(被动套接字):
它的作用是维护“套接字名”-即IP地址和端口号。服务器通过该套接字来接受连接请求。**但是!这个套接字不能用于发送或接受任何数据!**也不表示任何实际的网络会话,只是占着地方!接收通信请求后