了解 java.net.SocketException Broken Pipe 錯誤
1. 概述
在本教程中,我們將仔細研究 Java“ java.net.SocketException: “Broken pipe
”錯誤。在第一步中,我們將演示如何重現此異常。我們的下一步將是了解異常的主要原因,然後我們將了解如何解決此問題。
2. 實際例子
現在,讓我們看一個生成錯誤“ java.net.SocketException: “Broken pipe
”的示例。
簡而言之,當一個設備嘗試從另一台已失效或連接已斷開的設備讀取或寫入數據時,通常會發生管道損壞。
當連接關閉時,必須建立新的連接才能繼續傳輸數據。否則,數據將停止傳輸。
2.1.設置客戶端和服務器
為了在本地進行模擬,我們將使用一個Server
類作為我們的 Web 服務器,並使用一個Client
類作為我們的客戶端計算機。
一旦我們關閉服務器套接字,連接到該套接字的客戶端仍然會發送消息並接收錯誤消息。
如果服務器向客戶端發送一些響應,並且客戶端同時失去連接,也會發生這種情況。
第一步,讓我們創建一個名為Server
的服務器類,監聽端口1234
:
public class Server {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(1234);
System.out.println("Server listening on port 1234...");
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected: " + clientSocket.getInetAddress());
//Add some delay for reading from client
Thread.sleep(2000);
InputStream in = clientSocket.getInputStream();
System.out.println("Reading from client:" + in.read());
in.close();
clientSocket.close();
serverSocket.close();
}
catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
其次,讓我們創建一個客戶端Client
並將其附加到1234
端口套接字:
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 1234);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("HELLO".getBytes());
System.out.println("Writing to server..");
//Here we are writing again.
outputStream.write("HI".getBytes());
System.out.println("Writing to server again..");
System.out.println("Closing client.");
outputStream.close();
socket.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
在這裡,我們向服務器發送一些消息,服務器正在讀取並打印該消息。一旦我們運行服務器並啟動客戶端,我們就不會看到任何錯誤,因為在服務器關閉套接字之前發送了數據:
// Server console
Server listening on port 12345...
Client connected: /127.0.0.1
Reading from client:66
// Client console
writing to server..
writing to server again..
Closing client.
2.2.重現斷管錯誤
為了得到錯誤,讓我們延遲從Client
發送下一條消息,直到服務器關閉連接:
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 1234);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("HELLO".getBytes());
System.out.println("Writing to server..");
// Simulating a delay after writing to the socket
Thread.sleep(3000);
outputStream.write("HI".getBytes());
System.out.println("Writing to server again..");
System.out.println("Closing client.");
outputStream.close();
socket.close();
}
catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
讓我們再次運行它,看看服務器套接字已關閉,如果客戶端發送消息,則會返回一個損壞的管道錯誤:
// Server console
Server listening on port 12345...
Client connected: /127.0.0.1
Reading from client:66
// Client console
Writing to server..
java.net.SocketException: Broken pipe (Write failed)
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:143)
at <span class="pl-s1">com</span>.<span class="pl-s1">baeldung</span>.<span class="pl-s1">socketexception</span>.<span class="pl-s1">brokenpipe</span>.Client.main(Client.java:18)
3. 原因
此錯誤的一個示例是客戶端程序(例如加載網站的瀏覽器窗口)在從服務器完全讀取數據之前崩潰或終止。如果連接關閉,此後客戶端向服務器寫入數據的任何嘗試都會導致“管道損壞”錯誤。
對於網絡套接字,如果拔掉網絡電纜或另一端的進程無法正常工作,則可能會發生這種情況。在這種情況下,連接可能意外終止,或者網絡可能遇到問題。
就Java而言,沒有專門的BrokenPipeException
。此錯誤通常與其他錯誤捆綁在一起,例如SocketException
和IOException
。
客戶端失去連接可能有多種原因,包括在服務器響應之前關閉瀏覽器、服務器過載或響應時間過長。
4、解決方案
無法保證客戶端/服務器始終等待正常連接關閉。但是,仍然可以有效地處理管道破裂錯誤。
始終建議確保客戶端和服務器正確處理套接字連接並正常關閉流和套接字,以管理 Java 的“損壞的管道”錯誤。
我們還必須有效地管理超時并快速響應。
再次強調,沒有通用的解決辦法。我們需要找出根本問題並適當解決。
5. 結論
在本文中,我們了解了 Java 的“ java.net.SocketException Broken pipe
”錯誤。然後,我們討論了錯誤是如何產生的,並了解了異常的原因。最後,我們研究了處理錯誤的可能方法。
與往常一樣,本文的示例代碼可以在 GitHub 上獲取。