一些TCP协议的基础标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻把数据读走
RST:要求重新建立连接,也叫复位报文段
SYN:请求建立连接,同步报文段
FIN:通知要断开连接了我这里,结束报文段
一,确认应答
这是核心机制,但也比较简单,也就是你发送过去了一个数据是(1-1000),那边确认应答之后,给你回了一个(1001),就是告诉你下一个数据的开始序列是那个,也是这边确认收到了的意思。(确认应答也是ACK)
图:
二,超时重传
就比如你发送了一个消息,别人一直没有理你,你这边就想着是不是没有收到啊,再发了一次,这也就是超时重传。
也就是主机A这边发送了一个消息,在一个特定时间里面,主机B的确认应答一直没有发送过来,就会进行重新发送,以确保数据不会出现丢包。
但要注意的是也可能出现ACK丢失的情况,就会重复发了一段。这时候就需要去重了,接收方这边有一个数据结构叫做数据缓冲区,当有数据进入这个区,应用程序以read,就会把这个重复的从缓冲区删掉。
三,连接管理
分为建立连接和断开连接,
建立连接:三次握手:
也就是通信双方要互相保存对方的信息,具体完成需要三次网络交互。
首先发起请求方先发一次 同步报文,接受请求方在接受到了之后,向客户端发一个同步报文(SYN)+应答报文(ACK),在接受到服务器发的SYN+ACK之后,客户端这边在发一个应答报文(ACK)。
建立连接的意义:
投石问路,确认当前通信路径是否通畅。
协商参数,确认一些通信中必备的通信参数
具体做法是这样的:
断开连接也就是四次挥手,也就是客户端这边给服务器这边发送一个FIN(结束报文),进入了一个time_wait状态,如果出现大量的这个状态,就证明服务器触发了大量的主动断开TCP连接操作,服务器这边回一个(ACK)应答报文,这时服务器会进入一个close_wait状态,如果出现了大量close_wait状态,那就可能应用程序忘记调用close了,等客户端这边的应用程序代码执行到close的时候,再发一个(FIN),在客户端这边收到之后,就给服务器发一个ACK,告诉服务器我这边结束了,不要再联系了。
具体情况时这样的:
四,滑动窗口
这个好理解,在上面传输数据的时候,都是一个一个往过传输的,效率很慢,所以就需要一个加快传输效率的方法,滑动窗口就出现了,也就是把很多条数据一起发送过去,这样就降低了等待时间。
具体实现:
这边发送前五条数据的时候,不用等待ACK就直接发送。
窗口大小代表着继续发送数据的最大值,这边的就是4000
收到第一个ACK后就继续发送第五个数据以此类推
注意问题:
第一个,返回的ACK 丢了咋办,这个没事,后面还有一直跟着返回的ACK,客户端这边还能继续确认,不影响什么。
第二个,数据包丢了,比如第二个数据包2000丢了。这边ACK返回的全都是下一个是1001 ,如果客户端这边收到了三个这个,就会重新发送1001~2000这个数据包。这边接受到第二个数据包之后,直接返回的就是给你发的那个最后卡住的地方,前面的值已经接受到了,在接收缓冲区。这种机制也叫做高速重发控制(快重传)
拿图表示:
五,流量控制
接收端这边处理数据是有限的,如果接收端这边满了,发送端再发数据就很容易造成丢包,引起丢包重传的低效操作。
因此接收端这边就会把自己可以接收的缓冲区的大小放到TCP首部,也就是窗口大小,窗口越大,接收的数据越多,效率就越高,反之则越低。
一旦这边窗口满了,就会告诉客户端那边停止发送。
上图:
六,拥塞控制
和流量控制类似,都是启动了滑动窗口来进行控制,也就是站在接收方的角度,影响这发送方的速度,也就是一开始让你先发点,看没有丢包就继续加,加到窗口大的很,开始丢包了,就赶快减少,减少到不丢包为止,也就是在丢包的边缘疯狂试探。
上图:
七,延时应答
也就是ACK不会立即返回,会等一段时间再返回,这样也是为了提高传输效率,比如现在窗口的大小是5kb,这边传过来一个1kb的数据,如果立即返回ACK,那过去的窗口大小只有4kb,等一会应用程序可能把1kb的数据消费了,这是返回ACK就有5kb了。
此处延时有两种方法:
一种是按照一定时间来延时
第二个是按照接收到的数据量。
八,捎带应答
建立在演示应答基础上的提高效率的方法:
比如在客户端这边一般都是一问一答机制,但在延时应答的时候,ACK 等了一会会,这是给客户端的请求,ACK正好可以捎带着一起返回了,可以提高效率
九,面向字节流(粘包问题)
在字节流 读写数据的情况下,会涉及到一个很严重的问题,也就是粘包问题。
就比如你一次发送了好几个单词,比如dog,cat,hello。你发过去后,由于字节流,就可能一次读一个字节或者若干字节,所以可能给你读成dogcathello这种了。
此处粘的主要应用层的数据包,也就是要区分一个到一个应用层数据包之间的界限。
主要用两点:
1)使用分隔符,任何字符都可以,只要在数据中不存在的都可以
2)约定包的长度
十,异常情况
1)进程终⽌:进程终⽌会释放⽂件描述符,仍然可以发送FIN.和正常关闭没有什么区别.
2)机器重启:和进程终⽌的情况相同。
3)机器掉电/⽹线断开,接收端认为连接还在,⼀旦接收端有写⼊操作,接收端发现连接已经不在了,就会进⾏reset,即使没有写⼊操作,TCP⾃⼰也内置了⼀个保活定时器,会定期询问对⽅是否还在,如果 对⽅不在,也会把连接释放。