最近一个项目中使用socket通信传输数据,发现write()阻塞问题,经过调查是因为缓冲区堆积导致的,那么缓冲区为什么会堆积呢?
在我的代码中原因是:发送端发送数据的速度 > 接收端接收数据的速度。随着时间推移,导致发送端的数据量远远大于接收端数据量,导致了缓冲区堆积。
代码如下:
//连接socket服务端
private static Socket mSocket;
private static OutputStream mOutputStream;
private static InputStream mInputStream;
mSocket = new Socket(“10.10.10.5”, 6001);
mOutputStream = mSocket.getOutputStream();
mInputStream = mSocket.getInputStream();
…
//发送端写数据,速度快
mOutputStream.write(buffer);
…
//接收端读数据,速度慢
readSize = mInputStream.read(buffer);
当发送的数据量很大,接收端又没有及时的去读出数据,缓冲区就会堆积,最后造成write阻塞。
查看发送缓冲区大小:
cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304
发送端:已经发送到网络的数据需要暂存在send buffer中,只有收到接收端的ack后,系统内核才从send buffer中清除读走的这一部分数据,为后续的发送数据腾出空间。
接收端:接收端将收到的数据暂存在receive buffer中,自动进行确认,但如果socket所在的进程不及时将数据从receive buffer中取出,最终将导致receive buffer填满,由于TCP的滑动窗口和拥塞控制,接收端会阻止发送端向其发送数据。
对于应用程序app,如果继续发送数据,最终将导致send buffer填满,write阻塞。
结论:接收端程序读取数据的速度跟不上发送端发送数据的速度,最终将导致write调用阻塞。