有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

安卓 Java是否在等待stream完成编写?

我有一个用java运行的“服务器”,我通过字节数组向“客户端”(安卓系统)发送文件。该功能工作正常,但我注意到,当我尝试发送更大的文件(1MB+)时,它在关闭之前没有成功写入所有字节(例如:尝试发送5mb,但只发送902字节)。有没有办法让代码在关闭流之前等待流完成编写?下面是代码和堆栈跟踪。本质上,在附加和发送文件时(在处理GUI的类中)会调用send message方法。在本例中,我并没有试图从客户端接收数据,只是将数据发送到客户端

编辑:我知道我现在只将字节数组设置为1MB。我的手机是5MB,但它仍然只是在写<;1MB。即使是1MB,它仍然只能写入902字节

EDIT2:我在客户端发布了一些处理数据接收的代码

public void sendMessage(File file) {
    if(mOut != null) {
        try {
            FileInputStream inStream = new FileInputStream(file);               
            byte[] message = new byte[1024 * 1024];
            inStream.read(message);
            mOut.write(message, 0, message.length);
            mOut.flush();
            inStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
}

public void run() { 
    super.run();
    running = true;
    try {
        System.out.println("S: Connecting...");
        ServerSocket serverSocket = new ServerSocket(SERVERPORT);
        Socket client = serverSocket.accept();
        linked = true;
        System.out.println("S: Receiving...");

        try {
            mOut =client.getOutputStream();
            InputStream in = client.getInputStream();
            while(running) {
                byte[] message = new byte[1024 * 1024];
                 in.read(message);
                if(message != null && messageListener != null) {
                    messageListener.messageReceived(message);
                }
            }
        } catch (Exception ex) {
            System.out.println("S:Error");
            ex.printStackTrace();
        } finally {
            client.close();
            System.out.println("S:Done");
        }
    } catch (Exception ex) {
        System.out.println("S: Error");
        ex.printStackTrace();
    }

}
---------------------------------------------------------------------------
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at Server.sendMessage(Server.java:34)
at ServerBoard$2.actionPerformed(ServerBoard.java:57)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at Server.run(Server.java:58)

下面是客户端的代码片段

    public void run() {
    mRun = true;
    serverMessage = new byte[1024 * 1024];
    try {
        InetAddress serverAddr = InetAddress.getByName(SERVERIP);
        Log.e("TCP Client", "C:Connecting...");
        Socket socket = new Socket(serverAddr, SERVERPORT);
        try {
            in = socket.getInputStream();
            while(mRun) {
                 in.read(serverMessage);
                if(serverMessage != null && mMessageListener != null) {
                    mMessageListener.messageReceived(new String(serverMessage));
            }
                serverMessage = null;
            }

            Log.e("RESPONSE FROM SERVER","S:Received Message: '" + serverMessage + "'");

        } catch(Exception ex) {
            Log.e("TCP","S: Error", ex);
        } finally {
            socket.close();
        }
    } catch(Exception ex) {
        Log.e("TCP","C: Error", ex);
    }
}

共 (1) 个答案

  1. # 1 楼答案

    首先是read的JavaDoc:

    Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.

    由于源是一个套接字,它返回的字节可能比预期的少,即使缓冲区大小为1 MB,返回902 KB也是可以的。你必须循环直到流程结束

    以下方法读取所有字节,然后调用侦听器:

    byte[] message = new byte[0]; 
    byte[] buffer  = new byte[4096];
    int    len;
    while(( len = is.read( buffer )) > -1 ) {
       byte[] tmp = new byte[message.length+len];
       System.arraycopy( message, 0, tmp, 0, message.length );
       System.arraycopy( buffer , 0, tmp, message.length, len );
       message = tmp;
    }
    messageListener.messageReceived( message );
    

    正如您所见,发生了很多重新分配:您必须重新设计协议,首先发送文件大小,然后分配一次接收缓冲区