首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java Socket 傳檔案阻塞於 ObjectInputStream 建構子:雙向流初始化順序必須對稱

     編輯:程式設計疑難解答

現象:Client 端 `new ObjectInputStream(socket.getInputStream())` 卡住不動,Server 端對應行調整順序後就正常。根因是 **`ObjectInputStream` 建構子會阻塞等待對方寫入序列化標頭 (Stream Header)**。

阻塞原理

  • `ObjectInputStream(InputStream in)` 文件註明:*「在對應的 ObjectOutputStream 寫入並刷新標頭之前,此建構方法將阻塞。」*
  • Client 先 `new OIS` → 等 Server 寫標頭。
    Server 先 `new OIS` → 等 Client 寫標頭。
    **雙方同時等 → 死結**。

正確初始化順序:雙方**先建 OOS 再建 OIS**


// Client 端
Socket socket = new Socket("host", 8888);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.flush();                    // 關鍵:先推送標頭
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); // 此時不再阻塞

// Server 端
Socket socket = serverSocket.accept();
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.flush();                    // 關鍵:先推送標頭
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); // 此時不再阻塞

完整傳檔案流程範例


// Client
try (Socket s = new Socket("host", 8888);
     ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
     ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
     FileInputStream fis = new FileInputStream(file)) {

    oos.flush(); // 送標頭
    oos.writeUTF(file.getName());
    oos.writeLong(file.length());
    byte[] buf = new byte[8192];
    int len;
    while ((len = fis.read(buf)) > 0) oos.write(buf, 0, len);
    oos.flush();

    String ack = ois.readUTF(); // 等待 "OK"
    System.out.println(ack);
}

// Server
try (ServerSocket ss = new ServerSocket(8888);
     Socket s = ss.accept();
     ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
     ObjectInputStream ois = new ObjectInputStream(s.getInputStream())) {

    oos.flush(); // 送標頭
    String name = ois.readUTF();
    long len = ois.readLong();
    try (FileOutputStream fos = new FileOutputStream(new File("recv/" + name))) {
        byte[] buf = new byte[8192];
        int read, total = 0;
        while (total < len && (read = ois.read(buf)) > 0) {
            fos.write(buf, 0, read);
            total += read;
        }
    }
    oos.writeUTF("OK");
    oos.flush();
}

關鍵口訣

「雙向 ObjectStream,**雙方必須先 new OOS → flush() → 再 new OIS**,順序一致才不會互相等標頭卡死。」

記住這順序,Socket 序列化傳輸就不會再在建構子處莫名阻塞。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved