tcp向上层提供的数据肯定是按顺序排好的。比如一共有1 2 3 4 5五个包,假设前3个包的大小可以填满tcp的缓冲区,那么如果第4个包丢失,这时候并不会影响应用层接收前三个包。而如果是前三个包里面发生丢失,即使4 5都正常接收也不行,因为前面还有包没有收到,这时候tcp是不会向上层提供数据的。
这里面的关键是要了解tcp缓冲区,以及tcp所提供的顺序保证(这也是可靠性的一个方面)机制。
TCP建立采用的是三次握手。最近在看论文的时候,突然想到,如果第三个ACK报文丢失了,TCP建立是否还会成功?TCP是如何处理的呢?
三次握手的第三个ACK包丢了——客户端认为连接建立,写数据时,会触发RST
三次握手的第三个ACK包丢了——客户端认为连接建立,写数据时,会触发RST - 无影 - 激情、专注、坚持、思考
当Client端收到Server的SYN+ACK应答后,其状态变为ESTABLISHED,并发送ACK包给Server;
如果此时ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且依次等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。
Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5。
如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server自动关闭这个连接。
但是Client认为这个连接已经建立,如果Client端向Server写数据,Server端将以RST包响应,方能感知到Server的错误
Server 端
第三次的ACK在网络中丢失,那么Server 端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。
而Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5.
如果重发指定次数之后,仍然未收到 client 的ACK应答,那么一段时间后,Server自动关闭这个连接。
Client 端
在linux c 中,client 一般是通过 connect() 函数来连接服务器的,而connect()是在 TCP的三次握手的第二次握手完成后就成功返回值。也就是说 client 在接收到 SYN+ACK包,它的TCP连接状态就为 established (已连接),表示该连接已经建立。那么如果 第三次握手中的ACK包丢失的情况下,Client 向 server端发送数据,Server端将以 RST包响应,方能感知到Server的错误。
一个包丢了怎么处理
tcp协议关于发送数据包:
慢启动(slow start)机制,开始时发送较慢,然后根据丢包情况判断加快还是降低。
默认情况下,接受方每接受到两个tcp数据包就要发送一个acknowledgement 简称 ACK
ACK:
1.期待要收到的下一个数据包的编号
2.接收方的接受窗口剩余容量
握手过程中使用了 TCP 的标志(flag) —— SYN(synchronize) 和 ACK(acknowledgement)。 发送端首先发送一个带 SYN 标志的数据包给对方。接收端收到后, 回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发 送端再回传一个带 ACK 标志的数据包,代表“握手”结束。
丢了包:如果发送方发现受到三个重复的ACK或者超时了还没有收到任何ACK,就会确认丢包,从而再次发送这个包。