在有以下幾種情景,TCP會把ack包發出去:
1.收到1個包,啟動200ms定時器,等到200ms的定時器到點了(第二個包沒來),於是對這個包的確認ack被發送。這叫做“延遲發送”;
2.收到1個包,啟動200ms定時器,200ms定時器還沒到,第二個數據包又來了(兩個數據包一個ack);
3.收到1個包,啟動200ms定時器,還沒超時,正好要給對方發點內容。於是對這個包的確認ack就跟着捎過去。這叫做“捎帶發送”;
4.每當TCP接收到一個超出期望序號的失序數據時,它總是發送一個確認序號為其期望序號的ACK;
5.窗口更新或者也叫做打開窗口(接收端窗口達到最大的時候,接收緩存中的數據全部推向進程導致接收緩存為空),通知發送端可以繼續發送;
6.正常情況下對對方保活探針的響應,詳見TCP keepalive
有以下情況會發送RST包
1.connect一個不存在的端口;
2.向一個已經關掉的連接send數據;
3.向一個已經崩潰的對端發送數據(連接之前已經被建立);
4.close(sockfd)時,直接丟棄接收緩沖區未讀取的數據,並給對方發一個RST。這個是由SO_LINGER選項來控制的;
5.a重啟,收到b的保活探針,a發rst,通知b。
TCP socket在任何狀態下,只要收到RST包,即可進入CLOSED初始狀態。
值得注意的是RST報文段不會導致另一端產生任何響應,另一端根本不進行確認。收到RST的一方將終止該連接。程序行為如下:
阻塞模型下,內核無法主動通知應用層出錯,只有應用層主動調用read()或者write()這樣的IO系統調用時,內核才會利用出錯來通知應用層對端RST。
非阻塞模型下,select或者epoll會返回sockfd可讀,應用層對其進行讀取時,read()會報錯RST。
