浏览 5487 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-27
某程序: con = new Socket(ip, port);//一个socket InputStream socketIn = con.getInputStream(); InputStreamReader isr=new InputStreamReader(socketIn, "UTF-8"); while ((headchar = isr.read()) != -1) {// 读取报文头 用字符流来读取 headres += (char) headchar; ......//一些逻辑 处理报文头 } ... //报文头读完了 获取了报文体的大小等内容 开始读报文体 byte tempbuf[] = new byte[buffsize]; int start = 0; int tem = -1; //用字节流来读报文体 while ((tem = socketIn.read(tempbuf, start, buffsize)) != -1) { log.info("从"+start+"开始读"+buffsize); log.info("实际读取" + tem); if (tem < outparamsizes[i]) { start = start + tem; buffsize = buffsize - tem; ...//一些逻辑 处理报文体 读取完毕 } 这样的程序,在windows下正常工作,再放到linux下,读完报文头开始读取报文体的时候,并没有从报文体的开头开始读取,而是丢失了报文体前面的一些数据,导致读不到足够的数据直到超时。 经过一番调试和请教后发现原因:在linux下一个InputStream不能用字符流和字节流分段读取,因为linux下的字符由于utf8编码会多加几位,用字符读完报文头后其实就已经多读了许多位,再用字节读就丢掉多读的那部分了。 因此,只要将读取报文头的部分也改成字节流读取就可以了 while ((headchar = socketIn.read()) != -1) { ...} 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-03-27
不太建议在流操作的时候将InputStreamReader 和inputStream混用,甚至不建议将不通的Stream混用,除非你特别清楚这些流的封装类都做了什么。
还有你的报文头不是定长的?至少也有一个长度位吧。 while ((headchar = isr.read()) != -1)太不安全了 |
|
返回顶楼 | |
发表时间:2008-03-27
fool_leave 写道 不太建议在流操作的时候将InputStreamReader 和inputStream混用,甚至不建议将不通的Stream混用,除非你特别清楚这些流的封装类都做了什么。
还有你的报文头不是定长的?至少也有一个长度位吧。 while ((headchar = isr.read()) != -1)太不安全了 报文头有结束标识符 while里面有判断逻辑的 |
|
返回顶楼 | |
发表时间:2008-03-27
你的结束标示符是什么?
read动作如果返回的是-1,只能表明这次流数据结束,并不是标示你的数据已经到了结尾。换句话说你如果发送出1024个byte,但接收的地方很可能会接收到512个byte之后就读到-1. 这个和操作系统对io缓存的处理也有关系。具体的可能要看IO底层处理了。 即便 while ((tem = socketIn.read(tempbuf, start, buffsize)) != -1) 这句也可能不能正常执行,因为我们并不可以肯定再一次IO流的传输中就可以把全部的数据收到,也可能在还没有读到buffsize大小的数据前就收到了-1。所以应该明确知道自己有多少数据要接收,然后while循环里判断是不是全部收到了,而不是流数据是不是结尾了。 “在linux下一个InputStream不能用字符流和字节流分段读取,因为linux下的字符由于utf8编码会多加几位” 问题不是这个。不论哪个操作系统,都不会在流的数据上加减数据的。用UTF-8编码,也是在收到数据后encode而已。如果读取时设置了reader的编码格式,它会按照这个编码格式来读取word而不是读取byte,不同的编码格式,每个word的长度肯定不一样,这样就会出现将流错误截断的问题了。所以建议你不要将Reader/Writer和IOStream混用。甚至DataInputStream和InputStream在配合使用的时候也要小心。 建议操作流的时候Writer和Reader配对,他们是对字符做处理,而不是字节。 |
|
返回顶楼 | |
发表时间:2008-03-27
fool_leave 写道 你的结束标示符是什么?
read动作如果返回的是-1,只能表明这次流数据结束,并不是标示你的数据已经到了结尾。换句话说你如果发送出1024个byte,但接收的地方很可能会接收到512个byte之后就读到-1. 这个和操作系统对io缓存的处理也有关系。具体的可能要看IO底层处理了。 即便 while ((tem = socketIn.read(tempbuf, start, buffsize)) != -1) 这句也可能不能正常执行,因为我们并不可以肯定再一次IO流的传输中就可以把全部的数据收到,也可能在还没有读到buffsize大小的数据前就收到了-1。所以应该明确知道自己有多少数据要接收,然后while循环里判断是不是全部收到了,而不是流数据是不是结尾了。 read() Returns: the total number of bytes read into the buffer, or -1 is there is no more data because the end of the stream has been reached. 数据量大或者网络状况不佳的时候没有办法一次把buffsize(报文体大小)读回来,所以才有了下面的代码 log.info("从"+start+"开始读"+buffsize); log.info("实际读取" + tem); if (tem < outparamsizes[i]) { start = start + tem; buffsize = buffsize - tem; 根据每次读到的数据位移读取位置和读取量,直到读到的大小=buffsize 结束,while里的-1在正常情况下是不会遇到的。 这里的日志例如:从0开始读10000 实际读取3000 从3000开始读7000 实际读6000 从9000开始读1000 实际读1000 fool_leave 写道 “在linux下一个InputStream不能用字符流和字节流分段读取,因为linux下的字符由于utf8编码会多加几位” 问题不是这个。不论哪个操作系统,都不会在流的数据上加减数据的。用UTF-8编码,也是在收到数据后encode而已。如果读取时设置了reader的编码格式,它会按照这个编码格式来读取word而不是读取byte,不同的编码格式,每个word的长度肯定不一样,这样就会出现将流错误截断的问题了。所以建议你不要将Reader/Writer和IOStream混用。甚至DataInputStream和InputStream在配合使用的时候也要小心。 建议操作流的时候Writer和Reader配对,他们是对字符做处理,而不是字节。 同意你的观点,我一开始读报文头时候是用bufferedreader包装inputstream用readline()来读取报文头的,因为这样方便我判断报文头的结束,结束标识符是“[end header]”,结果当然是linux下流错误截断,我认为是bufferedreader缓冲了报文头结束后的那些数据,所以改成了inputstream。 通过这次也吸取教训了。 |
|
返回顶楼 | |