最近在一家公司做java实习,写了个网络字节采集器。写了个单例TCPServer来采集数据,其中用到了InputStream.read()来读取数据。产生了一系列问题,下面做下总结:
关于while((length = is.read(data)) != -1)问题。
在写此方法时,产生了一些疑惑,read何时阻塞?何时返回值-1?
首先做个假设:
1、读不满data的length就一直阻塞。为此,做了以下实验:
Server端:
byte[] data = new byte[8];
while((length = is.read(data)) != -1){
String result = new String(data);
System.out.println(result);
System.out.println("length:" + length);
}
客户端:
String msg = "ab";
byte[] byteMsg = msg.getBytes();
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream out = socket.getOutputStream();
BufferedOutputStream bw = new BufferedOutputStream(out);
for (int i = 0;i<10;i++) {
bw.write(byteMsg);
bw.flush();
}
发现服务端在length=2时,就输出了,结果为ab。说明并不是在data读不满时就一直阻塞。
2、那么是不是跟flush()有关呢?
下面将bw.flush()注视,发现,并追加代码Thread.sleep(5*1000),让它每次输出2个字节后暂停5秒,以达到网络很差的目的。发现服务端每次输出abababab 8个长度的字节。则可以判定跟flush有关。
3、那什么时候缓冲区的数据会flush呢?
和另一网络组的程序对接读数据,他每次都发送148个字节长度的数据,并循环一直发,而我这边依次解析148长度的数据。但发现时间久了数据就会对不拢。分析错误数据发现是没有读完148,而下次再读时将剩余没读完的部分加在了本次的头部,固然出错。于是有个疑问:我这边每次都是读148个字节,然后处理,为什么会有读不满148的情况?根据前两个的测试,初步判断跟flush有关。可能是网络层数据缓冲区在数据量超过一定范围时自动flush了。测试如下:
客户端:
String msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] byteMsg = msg.getBytes();
try {
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream out = socket.getOutputStream();
BufferedOutputStream bw = new BufferedOutputStream(out);
for (;;) {
bw.write(byteMsg);
//这里不进行程序flush,一直发。
}
服务端:
int count = 1000000;
is = socket.getInputStream();
byte[] data = new byte[count];
int length = 0;
while((length = is.read(data)) != -1){
String result = new String(data);
System.out.println(result);
System.out.println("length:" + length);
}
发现输出如下:
aaaaaaa..............行太长
length:39960
aaaaaaa..............行太长
length:23976
aaaaaaa..............行太长
length:23976
aaaaaaa..............行太长
length:24745
aaaaaaa..............行太长
length:25435
aaaaaaa..............行太长
length:21748
说明网络层缓冲区在长度一定时,就自动flush,但是这个长度好像不是很固定。长度取决于什么现在还不清楚。