对于InputStream,我第二次遇到这个非常恼人的问题。 此InputStream属于应该接收图像的Socket。阅读此图像的代码如下:
InputStream input = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
BufferedReader bufferedReader = new BufferedReader(reader);
int total = Integer.parseInt(bufferedReader.readLine());
int bytesRead = 0;
byte[] buffer = new byte[total]; // total is the total size of the image
while (bytesRead < total) {
int next = input.read(buffer, bytesRead, total-bytesRead);
if (next > 0) {
bytesRead += next;
System.out.println("Read: " + bytesRead);
}
}
现在奇怪的是,这段代码会跳过图像的前1182个字节,然后读取剩下的部分。因此,当total
大小为15000字节时,它会读取字节1182-15000。
我检查了Wireshark并传输了整个图像。代码不会引发异常。 input.read()
像往常一样返回-1。
使用BufferedReader
从流中提取过去的数据。这个数据只有5个字符,所以它不能包含丢失的1K,但我的猜测是BufferedReader.readLine()方法从InputStream读取(缓冲)更多的字节而不是需要的。这可能是正确的吗?
几个月前我遇到了同样的问题,但我完全不清楚我是如何解决它的。
希望任何人都可以提供帮助。
提前致谢。
编辑:我可以通过在发送图像大小和图像数据之间添加100毫秒的睡眠来解决问题。它解决了这个问题,但我仍然希望知道一个更合适的解决方案
答案 0 :(得分:3)
由于名称**Buffererd**Reader
表示它将比底层读取器中的第一行以及流中更多字节。否则,如果不被称为“缓冲”。
不幸的是,我不知道Java中有任何不推荐使用的类,它允许以你想要的方式混合二进制和文本数据。
我建议您修改协议并以一些二进制编码传输图像的长度。然后你可以坚持InputStream
。
答案 1 :(得分:0)
我的猜测是BufferedReader
将假设您之后执行的任何读取操作都将通过它,因此它会很乐意以缓冲区大小的增量消耗输入。
您可以做的一件事是在BufferedInputStream
之上使用input
,在DataInputStream
之上实例化readLine()
以执行BufferedInputStream
,然后使用{在你的循环中{1}}。文档说readLine
已被弃用,因为它没有正确地将字节转换为字符,但我希望你的第一行只包含十进制数字,它不应该遇到这个问题。
我写了一个简短的测试,我希望它涵盖你的用例:
import java.net.*;
import java.io.*;
class test{
static byte[] b;
static {
b = new byte[123456];
java.util.Random r = new java.util.Random();
for (int i=0;i<b.length;i++)
b[i] = (byte)(r.nextInt());
}
static void client() throws Exception{
Socket socket = new Socket("127.0.0.1", 9000);
InputStream input = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(input);
//read in length
DataInputStream dais = new DataInputStream(bis);
int total = Integer.parseInt(dais.readLine());
System.out.println("Total: "+total);
int bytesRead = 0;
byte[] buffer = new byte[total];
while (bytesRead < total) {
int next = bis.read(buffer, bytesRead, total-bytesRead);
if (next > 0) {
bytesRead += next;
System.out.println("Read: " + bytesRead);
}
}
for (int i=0;i<buffer.length;i++)
if (buffer[i]!=b[i]){
System.err.println("Error");
System.exit(1);
}
System.out.println("OK");
bis.close();
socket.close();
}
static void server() throws Exception{
ServerSocket srv = new ServerSocket(9000);
Socket sock = srv.accept();
OutputStream os = sock.getOutputStream();
BufferedOutputStream bos =new BufferedOutputStream(os);
DataOutputStream daos = new DataOutputStream(bos);
//we're sending the b buffer
//send the length in plain text, followed by newline
byte[]num = String.valueOf(b.length).getBytes();
daos.write(num,0,num.length);
daos.write(10);
//send actual buffer contents
bos.write(b, 0, b.length);
os.close();
srv.close();
sock.close();
}
public static void main(String[]args){
new Thread(new Runnable(){
public void run(){
try{server();}catch(Exception e){e.printStackTrace();}
}
}).start();
new Thread(new Runnable(){
public void run(){
try{client();}catch(Exception e){e.printStackTrace();}
}}).start();
}
}
答案 2 :(得分:0)
您是否考虑过仅发送图像数据(没有前面的图像尺寸)并使用Apache Commons IO之类的外部库来为您处理此问题?特别是,我认为你会发现IOUtils.toByteArray(InputStream input)有趣,例如
InputStream input = socket.getInputStream();
byte[] buffer = IOUtils.toByteArray(input);