Socket斷開不報錯(Java)


網上看了很多關於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;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM