14读缓冲区(滑动窗口)耗尽与write阻塞、拆包、延迟(三)禁用nagle仍发送端沾包
本文设计了一个案例,证明禁用nagle的情况下,并非所有情况都不会导致发送端沾包
在 读缓冲区(滑动窗口)耗尽与write阻塞、拆包、延迟(二)的代码上,使用默认发送缓冲区大小,并禁用nagle,这是第三种情况,前2种在11读缓冲区(滑动窗口)耗尽与write阻塞、拆包、延迟(一)中
// s.setSendBufferSize(BUFFER_SIZE); /** * 禁用nagle,可连续发包 */ s.setTcpNoDelay(true);
服务端,12s后直接打印到:
96
97
98
99
100
101
102 由于各种拆包多了3个包
客户端:
无阻塞直接打印到
send + 97
send + 98
send + 99
Process finished with exit code 0
结论:
1 客户端发送缓冲区够大,即使对端窗口耗尽,也没导致write阻塞
再次“证明了接收窗口不够时,一些情况会导致write阻塞,但不是直接因为对端接收窗口不够了,而是因为对端窗口导致本方发送缓冲区积压至满,只要内核发送缓冲区够大,write就能返回,不会由于对端不接收数据而直接阻塞”
2 12s后,服务端开始读,通知客户端有空间了
3 客户端一口气连发一堆,1152+1072*8+272=10000(禁用nagle情况下,发送端也沾包了)
4 write只是将数据从用户态拷贝到了内核态,不保证能立即发送(报文17 52个字节延迟5s发送),甚至能否发送(超出1152长度的其它包)
5 程序正常结束时tcp连接还会继续保持(本例抓到包了),程序会隐式close socket(本例发出fin包),什么时候发,发之前是否先等缓冲区全部发送完,发fin还是rst,由tcp协议及(默认SoLinger== -1会等,发fin包)控制