Java Socket(断开不报错版)

网上看了很多关于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;

就以客户端为例:完整代码如下(根据需要自行增减):

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;
    }
}

原文地址:https://www.cnblogs.com/vingxu/p/10740355.html

时间: 2024-08-29 21:28:14

Java Socket(断开不报错版)的相关文章

Java中List.remove报错UnsupportedOperationException

Java中List.remove(removeRange,clear类似) 报出 UnsupportedOperationException 的错误.原来该List是一个AbstractList,不支持增删改操作. 一般情况下我们会使用 LinkedList 和 ArrayList ,什么情况下出现 AbstractList 呢?通过 ArrayList.asList() 函数得到的 List 就是 AbstractList.该AbstractList只是简单地在已有的元素数组上套了一层List

用java运行Hadoop程序报错:org.apache.hadoop.fs.LocalFileSystem cannot be cast to org.apache.

用java运行Hadoop例程报错:org.apache.hadoop.fs.LocalFileSystem cannot be cast to org.apache.所写代码如下: package com.pcitc.hadoop; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.h

交通银行 Java Socket 服务启动 管理 WINDOWS 版

按照交通银行提供的无界面启动方法试验了很多次,都没有成功,所以自己动手用C# 知识写了一个. 小工具可以判断 交通银行 JAVA SOCKET 服务是否启动,并可以启动/关闭服务 主要代码如下: 判断服务是否启动 引用 :using System.Management; SelectQuery selectQuery = new SelectQuery(“select * from Win32_Process where Name = ‘java.exe’”); object cmdLine =

针对Flex+Java使用RemoteObject通讯 报错Channel.Connect.Failed error NetConnection.Call.Failed 404

今天在Flex中使用RemoteObject进行java调用时,报错 [RPC Fault faultString="Send failed" faultCode="Client.Error.MessageSend" faultDetail="Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 404: url: 'http://localhost:8080/UnitCi

java连接MySQL运行报错The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than

错误:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than 原因:time zone 时区错误 解决方法: 1.使用root用户登录mysql,输入下面命令. show variables like '%time_zone%';SYSTEM为SQL默认美国时间,而我们中国要比他们迟8小时 2.SYSTEM为SQL默认美国时间,而我们中国要比他们迟8小时,因此将时区设置为当前系统时区即可,

java数据库执行迁移报错Error creating bean with name 'flywayInitializer' defined in class path resource

报错原因 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocati

Java练手项目报错集锦(IDEA版)

1.URI is not registered (Settings | Languages & Frameworks | Schemas and DTDs) 有时候写spring配置文件的时候,会出现了上面这个错误 解决的具体方法如下: ①点击file-->settings...-->languages & frameworks-->Schemas and DTDs ②选中红框中的“+”,将报错的链接加入列表中, 2.Servlet should have a mappi

java.lang.NoSuchFieldError: VERSION_2_3_0 报错解决方案

java.lang.NoSuchFieldError: VERSION_2_3_0 at org.apache.struts2.views.freemarker.FreemarkerManager.createConfiguration(FreemarkerManager.java:331) at org.apache.struts2.views.freemarker.FreemarkerManager.init(FreemarkerManager.java:282) at org.apache

Java调用https服务报错unable to find valid certification path to requested target的解决方法

我们网站要进行https改造,配置上购买的SSL证书后,浏览器访问正常,但是写了个java代码用httpcomponents调用https rest接口时报错: Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath