網上看了很多關於Socket的Demo,用起來挺好用也簡單,不過都在斷開連接時,都沒有做好相關處理,導致每次主動斷開時,會報錯
如:
java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.idea_a.its.robot.http.SocketUtil.connectionData(SocketUtil.java:136)
at com.idea_a.its.robot.TryBServer$1$1.success(TryBServer.java:38)
at com.idea_a.its.robot.http.SocketUtil.connectSocket(SocketUtil.java:55)
at com.idea_a.its.robot.TryBServer$1.run(TryBServer.java:34)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
具體原因是在執行socket.close();的同時,相關的BufferedReader還在等待接收數據。
所以在斷開之前需要執行相關輸入輸出的關閉動作。
socket.shutdownInput();
socket.shutdownOutput();
並需要確保都關閉后(socket.isInputShutdown() socket.isOutputShutdown()),
才進行BufferedReader的關閉,
最終才是關閉socket;
代碼如下:
/** * 關閉 */ public void close() throws IOException { if (socket == null) return; socket.shutdownInput(); socket.shutdownOutput(); do { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } while (!socket.isInputShutdown() || !socket.isOutputShutdown()); br.close(); socket.close(); socket = null; }
就以客戶端為例:完整代碼如下(根據需要自行增減):
package com.bug01.trysocket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; public class SocketClientUtil { private static final String ADDRESS = "127.0.0.1"; private static final String PORT = "6666"; private Socket socket = null; private BufferedReader br; private static SocketClientUtil instance = null; // 此處使用單例模式 public static SocketClientUtil getInstance() { if (instance == null) { synchronized (SocketClientUtil.class) { if (instance == null) { instance = new SocketClientUtil(); } } } return instance; } /** * 連接socket */ public void connectSocket(SocketConnCallBack back) throws IOException { try { socket = new Socket(ADDRESS, Integer.parseInt(PORT)); back.success(); } catch (IOException e) { e.printStackTrace(); back.failure(); socket = null; } catch (Exception e) { e.printStackTrace(); back.failure(); } } /** * 發送數據 * * @param message */ public void sendData(String message) throws IOException { //判定是否socket已鏈接,如果未鏈接則嘗試鏈接。 if (socket == null) { connectSocket(new SocketConnCallBack() { @Override public void success() { } @Override public void failure() { } }); } //如果嘗試鏈接失敗,則上報異常。 if (socket == null) { throw new IOException("Socket Connect to Server Error."); } //輸出流 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); //向服務端寫入數據 pw.println(message); pw.flush(); } /** * 接受數據 */ public void SetListener(SocketCallBack back) throws IOException { //輸入流 InputStream is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); //接收服務器的相應 String reply = null; while (!((reply = br.readLine()) == null)) { back.responseData(reply.trim()); } } /** * 關閉 */ public void close() throws IOException { if (socket == null) return; socket.shutdownInput(); socket.shutdownOutput(); do { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } while (!socket.isInputShutdown() || !socket.isOutputShutdown()); br.close(); socket.close(); socket = null; } public interface SocketCallBack { void responseData(String data); } public interface SocketConnCallBack { //socket連接成功 void success(); //socket鏈接失敗 void failure() throws IOException; } }