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.BufferedReader;
import java.io.Closeable;
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 implements Closeable {
    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());
        }
    }

    /**
     * 关闭
     */
    @Override
    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;
    }
}

 

posted @ 2019-04-20 11:29  蜜铀  阅读(1243)  评论(0编辑  收藏  举报