最近,写的报文j接收过程。错误代码如下:
byte[] mesLength=new byte[2];
while((i=in.read(mesLength)) != -1) {
if(i<2) break;
int length=conv.byteToInt(mesLength);
byte[] mes=new byte[length];
int j=in.read(mes);
if(j!=length) break;
......
}
我的本意是,先从流里读出2个字节的长度,而后读出该长度的报文内容。
而此处,我的判断条件i<2,本意是如果流里只有一个字节,则停止接收,还有下面,“int j=in.read(mes)”本意也是如果流结束前,没有读到指定长度,则停止接收。没有异常的情况下,或许你觉得这样理所当然。但是这正是对java流的一种错误理解。
“in.read()"会从输入流读取信息,但是一次read可能由于异常等,并不能得到我们需求的字节数,因而正确的读法是:
int bytesRead = 0; //已读到字节数
int bytesToread =1024; //需求字节数
byte[] input = new byte[bytesToRead];
while ( bytesRead < bytesToRead ){
bytesRead + = in.read(input, bytesRead,bytesToRead-bytesRead);
}
按照上面的读法,我们才能读到需求的字节数。通过一次读取,可能由于某些原因并不能得到需求长度的字节数。这是我以上代码的一个错误。而另一个错误,则是判断流里数据的长度时无意义的。因为在下一次循环之前,我们都不能确定,流是否读完,下一次也不能确定。我们的流,就是简单的用来接收数据的,我们不该把对报文长度的校验放到此处,那么我们该如何处理呢,我们可以设置超时,这样,当一直读取不到需求长度的字节时,我们就可以关闭本次连接了。这样,即使我们是多线程处理,也可以保证受到上述错误格式攻击时,不会由于开启大量线程,而耗尽资源。
当然,这也与我初始定义的应答码有关,应答码中有个格式错误,经过上述考虑,格式错误可以取消。
上文仅供抛砖引玉,望多多指教。