首页 文章

DataInputStream的结果不一致

提问于
浏览
0

我在Java中使用DataInputStream和DataOutputStream时遇到了一个问题,如果没有一些非常愚蠢的措施我一直无法解决这个问题,并且想知道是否有人知道更好的方法(我非常确定有一个,但我还没有能够找到它) .

背景:我希望能够将Json字符串发送到服务器并让服务器将该字符串解析为对象 . 这需要与语言无关,因为我正在研究的项目需要我有一个异构系统 .

为了显示我的问题的最简单的可能示例,我将排除Gson / Json等的创建,因为它可以使用任何字符串重新创建 . 代码如下:

public class ServerSide {
    private final int PORT = 5001;
    private ServerSocket servSock;
    private Socket sock;
    private DataInputStream dis;
    private DataOutputStream dos;

    public ServerSide() throws IOException {
        servSock = new ServerSocket(PORT);
    }

    public void startListening() {
        try {
            sock = servSock.accept();
            dis = new DataInputStream(sock.getInputStream());
            byte[] bytes = new byte[1024];

            dis.read(bytes);

            String receivedMessage = new String(bytes);
            System.out.println("Message received: " + receivedMessage);
            sock.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

一个简单的测试类,它创建一个ServerSide()并在一段时间内调用startListening(true) .

public class ClientSide {
    private final int PORT = 5001;
    private Socket socket;
    private DataOutputStream dos;

    public ClientSide() {

    }
    public void sendMessage(String m) {
        try {
            socket = new Socket("127.0.0.1", PORT);
            dos = new DataOutputStream(socket.getOutputStream());
            dos.writeBytes(m);
            System.out.println("Message sent: " + m);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

一个简单的测试类,它创建ClientSide()对象并调用sendMessage(“这是一个测试消息”);

我遇到的问题是我只收到服务器端的部分消息 . 我不确定这是输入或输出流的问题,只能通过多次写入和读取数据并修剪其间的空白来找到解决方法 . 我的第一个问题是当我尝试将Json字符串发送到我在c#中编写的程序时,它会始终发送第一个字符(“{”),然后在下一次读取时发送其余字符串 . 我通过发送一个空格然后在服务器端忽略它来反击这一点 . 当在第一次读取时读取看似随机数量的字符串时,java-java上的问题变得更糟 .

服务器端上述代码的一些示例输出是:

Message received: This is a tes

Message received: T

Message received: T

Message received: T

2 回答

  • 1

    感谢@Illya Kysil提供的帮助我通过将代码更改为:找到了解决方案:

    public class ClientSide {
        private final int PORT = 5001;
        private Socket socket;
        private DataOutputStream dos;
    
        public ClientSide() {
    
        }
        public void sendMessage(String m) {
            try {
                socket = new Socket("127.0.0.1", PORT);
                dos = new DataOutputStream(socket.getOutputStream());
                byte[] mBytes = m.getBytes();
                dos.writeInt(mBytes.length);
                dos.write(mBytes);
                System.out.println("Message sent: " + m);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    

    public class ServerSide {
        private final int PORT = 5001;
        private ServerSocket servSock;
        private Socket sock;
        private DataInputStream dis;
        private DataOutputStream dos;
    
        public ServerSide() throws IOException {
            servSock = new ServerSocket(PORT);
        }
    
        public void startListening() {
            try {
                sock = servSock.accept();
                dis = new DataInputStream(sock.getInputStream());
                int length = dis.readInt();
                byte[] bytes = new byte[length];
                dis.readFully(bytes);
                String receivedMessage = new String(bytes);
                System.out.println("Message received: " + receivedMessage.trim());
                dis.close();
                sock.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
    
    }
    

    这将首先发送一个等于发送消息的字节数组大小的整数 . 可以在服务器端创建具有此长度的缓冲区,并且可以使用DataInputStream的readFully方法来填充此缓冲区 .

  • 1

    is.read(bytes); may return any number of bytes - 从1到 bytes.length .

    从输入流中读取一些字节数并将它们存储到缓冲区数组b中 . 实际读取的字节数以整数形式返回 . 此方法将阻塞,直到输入数据可用,检测到文件结尾或引发异常 .

    需要重复调用此方法,直到它返回 -1 ,这意味着流结束 .

    Reading from and Writing to a Socket提供了有关如何读取面向行的交换中的所有数据的示例 . 对于二进制数据(DataStream实际生成的),您需要使用ByteArrayOutputStream,ByteArrayInputStream和DataInputStream的组合:

    InputStream sis = sock.getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    while (int len = sis.read(bytes) > 0) {
        baos.write(bytes, 0, len);
    }
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    DataInputStream dis = new DataInputStream(bais);
    byte[] vBytes = new byte[baos.size()];
    int sLen = dis.read(vBytes);
    String receivedMessage = new String(vBytes, 0, sLen);
    System.out.println("Message received: " + receivedMessage);
    

    注意:上面的代码是回答特定问题 . 不要把它投入 生产环境 :)

相关问题