我们在写输入输出流中经常是以循环读取到-1作为结束符。
这个在文件的读写中,是没有问题的,很显然文件有结束符。
这个在socket通讯中,是有问题的,socket.getInputStream().read(buffer)这个函数,会处于阻塞状态,继续等待对方发数据过来。显然不可能中断,即使发一个-1,read也会把-1当作一个值读出来,循环仍将继续。
网上有一个解决方法:利用socket.setSoTimeout(),在第一次读取数据后,超过指定的时间,将发生异常,这时候,捕获异常,使程序继续进行。
我一个同事这样处理:利用inputStream.available(),来判断inputStream中是否还有可读取的值,如果没有,则跳出循环。
这两种做法都有弊端。
第一种做法,本生逻辑上就不合正常的思维,一般来说,我们是要避免抛异常的,这样做会使得程序写起来很别扭,理解起来也相对困难。另外,我们一般是通过传InputStream作为参数的,如private byte[] getEncodedData(InputStream is),这个时候,就必须传sokcet作为参数,不合逻辑。其它的就不再说了。
第二种做法:根据jdk提供的文档,Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. 这句话说明,这个available值不可靠。
后来,也是网上的朋友有仔细思考过这个问题,我仔细查看socket函数,可利用socket.shutdownOutput(),可以很好的解决这个问题。此函数可以,禁用此套接字的输出流。对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。 如果在套接字上调用 shutdownOutput() 后写入套接字输出流,则该流将抛出 IOException。
后来我仔细想了想。
这种通用问题,别人应该也碰过,应该有已经解决的方法,不过我在google和baidu上找了好多网页,才发现这个提示,而这个提示的来源,还是国外的,呵呵。另外既然是通用问题,写socket类的人是否已经意识到,并提供解决方案呢,这显然已经得到印证。
下面是关键代码,已经测试通过,因为是项目中代码,没法给全代码,想实现的同学,自己补充完善,网上很多,自己写也不难。
服务端:
/**
* 此方法用于从输入流中获取数据
*
* @param is 接收来自客户端socket对应的输入流
* @return 返回endodedData
* @throws IOException 抛出的异常,统一在run函数处理
*/
private byte[] getEncodedData(InputStream is) throws IOException {
byte[] maxBuffer = new byte[1024 * 64];
int length = 0;
int lengthTemp = 0;
while (-1 != (lengthTemp = is.read(maxBuffer))) { // read方法并不保证一次能读取1024*64个字节
length += lengthTemp;
if (length >= 1024 * 64) {
logger.debug("读入的数据超过1024 * 64");
break;
}
}
byte[] endodedData = new byte[length];
System.arraycopy(maxBuffer, 0, endodedData, 0, length);
logger.info("receiveData:" + DataUtil.bytesToHexString(endodedData) + '\n');
return endodedData;
}
客户端:
......
os.write(encodedData);
os.flush();
socket.shutdownOutput();
......
参考资料:
java Socket InputStream 阻塞 问题 :http://charseller.iteye.com/blog/941350
java InputStream读取数据问题 :http://www.cnblogs.com/MyFavorite/archive/2010/10/19/1855758.html
读取InputStream输入流的例子 :http://xuzw13.blog.163.com/blog/static/103147165201152010224717/
粗浅理解,还望同学们指正。
欢迎阅读相关文章: http://hi.youkuaiyun.com/linchengzhi