浅谈java socket的正确关闭姿势

java socket对应的是网络协议中的tcp,tcp的三次握手、四次挥手、11中状态什么的这里就不说了,不知道大家平常使用socket的时候如果不注意的情况下,会不会遇到各种异常报错。

例如:

java.net.SocketException:socket is closed

错误提示的出现场景:

自己主动关闭了socket,但是之后还从里面读写数据

Software caused connection abort: socket write error

错误提示的出现场景:

对方已经关闭socket,依旧向对方写数据

connection reset (by peer)

错误提示出现的场景:

一端socket被关闭,另一端仍然发送数据,发送的第一个数据包 connection reset by peer

一端socket退出,退出时为关闭连接,另一端读数据 connection reset

所以在使用socket时,需要约定好双方读写完成的条件,然后关闭输入输出流:

socket.shutdownInput();
socket.shutdownOutput();

即当一方写入完成后,调用shutdownOutput关闭输出流,这时候对方的read方法就会返回-1,这时候对方就知道你写完了,对方可以关闭输入流,然后等待对方写入完成调用shutdownOutput后己方再调用shutdownInput,双方就正常关闭了输入输出流,这时候socket就不会出现异常了。

下面是一个socket交互的例子:

server端

public class OioServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("socket = " + socket);
            new Thread(() -> {
                try {
                    InputStream in = socket.getInputStream();
                    OutputStream out = socket.getOutputStream();
                    out.write("hello! I get your message that is follow".getBytes(Charset.forName("UTF-8")));
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = in.read(buf)) != -1) {
                        System.out.print(new String(buf, 0, len, Charset.forName("UTF-8")));
                        out.write(buf, 0, len);
                    }
                    out.write("\n end \n".getBytes(Charset.forName("UTF-8")));
                    out.flush();
                    socket.shutdownInput();
                    socket.shutdownOutput();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

client端

public class OioClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 8080);
        InputStream in = socket.getInputStream();
        new Thread(() -> {
            BufferedInputStream bufferIn = new BufferedInputStream(in);
            byte[] buf = new byte[1024];
            try {
                int len;
                while ((len = bufferIn.read(buf)) != -1) {
                    System.out.print(new String(buf, 0, len, Charset.forName("UTF-8")));
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try {
                socket.shutdownInput();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
        OutputStream out = socket.getOutputStream();
        int cout = 10;
        while (cout-- > 0) {
            out.write(("this time is " + System.currentTimeMillis() + "\n").getBytes("UTF-8"));
        }
        socket.shutdownOutput();
    }
}

java socket - 半关闭

通常,使用关闭输出流来表示输出已经结束。但在进行网络通信时则不能这样做。因为我们关闭输出流时,该输出流对应的Socket也将随之关闭,这样程序将无法再从该socket中读取数据。

为了应付这种情况,socket提供了两个半关闭的方法用来只关闭socket的输入流或者输出流,用以表示输出数据已经发送完成。

方法详情:

shutdownInput():关闭该socket的输入流,程序还可以通过该socket的输出流输出数据;

shutdownOutput():关闭该socket的输出流,程序还可以通过该socket的输入流读取数据。

当调用shutdownInput()或shutdownOutput()方法关闭输入流或输出流后,该socket处于半关闭状态。

此时可以使用isInputShutdown()或isOutputShutdown()来判断该socket是否处于半读状态或半写状态。

需要注意的是,即使同一个socket先后调用shutdownInput()和shutdownInput()方法,该socket实例仍然没有被关闭,只是该socket既不能输出数据也不能读取数据而已。

当调用shutdownInput()或shutdownOutput()方法关闭了输入流或输出流之后,该socket无法再次打开输出流或输入流,因此这种做法不适合需要保持持久通信状态的交互式应用。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java Socket实现简易聊天室

    Java-Socket编程实现简易聊天室(TCP),供大家参考,具体内容如下 实现一个服务器接收多个客户端 测试: 首先启动服务器,然后启动三个客户端,输入三个不同的用户名,分别在聊天室发消息 看其他客户端是否能接收到消息 效果如下图: 一号发消息 可以在二号和三号客户端接收到消息 服务器设计 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ja

  • Java通过Socket实现简单多人聊天室

    本文实例为大家分享了Java通过Socket实现多人聊天室的具体代码,供大家参考,具体内容如下 Socket可以实现网络上两个程序通过双向通道进行数据的交换,此外它是Java中网络TCP/IP协议的封装,例如可以进行网络通信等等,下面我们就来简单写一下多人聊天室. 首先来分析一下要实现的流程 首先建立一个服务器端,构建ServerSocket并绑定端口 创建socket客户端,连接到指定ip以及其端口 然后使用accept阻塞接收socket发出的连接请求 获取连接后的socket客户端的输入流

  • 详解Java Socket通信封装MIna框架

    核心类 IoService :Mina中将服务端和客户端都看成是服务,这里提供统一接口IoService,这个接口的作用就是用来处理套接字机制.也正是IoService来监听消息返回消息这些步骤,可以说IoService就是我们Mina中核心 IoProcessor:这个接口在另一个线程上,负责检查是否有数据在通道上读写,也就是说它也拥有自己的Selector,这是与我们使用JAVA NIO 编码时的一个不同之处,通常在JAVA NIO 编码中,我们都是使用一个Selector,也就是不区分Io

  • 教你怎么使用Java实现WebSocket

    一.WebSocket简介 WebSocket协议通过在客户端和服务端之间提供全双工通信来进行Web和服务器的交互功能. 在WebSocket应用程序中,服务器发布WebSocket端点,客户端使用url连接到服务器.建立连接后,服务器和客户端就可以互相发送消息.客户端通常连接到一台服务器,服务器接受多个客户端的连接. 1.1 WebSocket协议 WebSocket协议有两个部分:握手和传输.客户端通过向服务端URL发送握手请求来建立连接.握手与现有的基于HTTP的基础结构相兼容.Web服务

  • Java Socket实现Redis客户端的详细说明

    Redis是最常见的缓存服务中间件,在java开发中,一般使用 jedis 来实现. 如果不想依赖第三方组件,自己实现一个简单的redis客户端工具,该如何实现呢?本文就是介绍这样一种方法. Redis的协议非常简单,而且输入数据和输出数据都遵循统一的协议,具体规则参考这里: http://redisdoc.com/topic/protocol.html Redis的命令协议: $参数数量n $参数1的值的字节数组长度 $参数1的值的字符串表示 $参数2的值的字节数组长度 $参数2的值的字符串表

  • Java 实现简单Socket 通信的示例

    目录 1. 传输层协议 2. TCP 示例 2.1 示例效果 2.2 服务端程序代码 3. UDP 示例 3.1 服务端程序代码 3.2 客户端程序代码 Java socket 封装了传输层的实现细节,开发人员可以基于 socket 实现应用层.本文介绍了 Java socket 简单用法. 1. 传输层协议 传输层包含了两种协议,分别是 TCP (Transmission Control Protocol,传输控制协议) 和 UDP (User Datagram Protocol,用户数据报协

  • java利用socket通信实现Modbus-RTU通信协议的示例代码

    Modbus Modbus是一种串行通信协议.Modbus 一个工业上常用的通讯协议.一种通讯约定.Modbus协议包括RTU.ASCII.TCP.其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现. 简单分析Modbus-RTU报文 37 03 10 3F 80 00 00 00 00 00 00 3F 80 00 00 40 40 00 00 24 dd(十六进制) 37:从站地址 ,03:功能码,10:读取的字节数,24 dd:crc校验码.其它就是传送的数据. 4G DTU(

  • Java 基于TCP Socket 实现文件上传

    文件上传过程一个单向Socket通信过程.客户端通过文件输入流读取文件,然后从Socket获取输出流写入数据.服务端从Socket中获得输入流,然后写入文件输出流,写入数据完成则上传完成. 服务端UploadServer: public class UplaodServer { public static void main(String []args){ try( // 创建一个ServerSocket监听8080端口的请求 // ServerSocket 实现了 AutoCloseable接

  • 浅谈java socket的正确关闭姿势

    java socket对应的是网络协议中的tcp,tcp的三次握手.四次挥手.11中状态什么的这里就不说了,不知道大家平常使用socket的时候如果不注意的情况下,会不会遇到各种异常报错. 例如: java.net.SocketException:socket is closed 错误提示的出现场景: 自己主动关闭了socket,但是之后还从里面读写数据 Software caused connection abort: socket write error 错误提示的出现场景: 对方已经关闭s

  • 浅谈Java关闭线程池shutdown和shutdownNow的区别

    目录 前言 项目环境 1.线程池示例 2.shutdown 3.isShutdown 4.isTerminated 5.awaitTermination 6.shutdownNow 7.shutdown 和 shutdownNow 的区别? 前言 本章分为两个议题 如何正确关闭线程池 shutdown 和 shutdownNow 的区别 项目环境 jdk 1.8 github 地址:https://github.com/huajiexiewenfeng/java-concurrent 本章模块:

  • 浅谈Java中hashCode的正确求值方法

    本文研究的主要是Java中hashCode的正确求值方法的相关内容,具体如下. 散列表有一项优化,可以将对象的散列码(hashCode)缓存起来,如果散列码不匹配,就不会检查对象的等同性而直接认为成不同的对象.如果散列码(hashCode)相等,才会检测对象是否相等(equals). 如果对象具有相同的散列码(hashCode),他们会被映射到同一个散列桶中.如果散列表中所有对象的散列码(hashCode)都一样,那么该散列表就会退化为链表(linked list),从而大大降低其查询效率. 一

  • 浅谈java 单例模式DCL的缺陷及单例的正确写法

    1 前言 单例模式是我们经常使用的一种模式,一般来说很多资料都建议我们写成如下的模式: /** * Created by qiyei2015 on 2017/5/13. */ public class Instance { private String str = ""; private int a = 0; private static Instance ins = null; /** * 构造方法私有化 */ private Instance(){ str = "hell

  • 浅谈java异常处理之空指针异常

    听老师说,在以后的学习中大部分的异常都是空指针异常.所以抽点打游戏的时间来查询一下什么是空指针异常 一:空指针异常产生的主要原因如下: (1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在 (2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在 (3)字符串变量未初始化: (4)接口类型的对象没有用具体的类初始化,比如: List lt:会报错 List lt = new ArrayList():则不会报

  • 浅谈Java开发中的安全编码问题

    1 - 输入校验 编码原则:针对各种语言本身的保留字符,做到数据与代码相分离. 1.1 SQL 注入防范 严重性高,可能性低. (1) 参数校验,拦截非法参数(推荐白名单): public String sanitizeUser(String username) { return Pattern.matches("[A-Za-z0-9_]+", username) ? username : "unauthorized user"; } (2) 使用预编译: Stri

  • 浅谈Java中File文件的创建以及读写

    1.创建一个文件 @Test public void test6() throws IOException { File file1 = new File("C:\\IDEA\\h1.txt"); if(!file1.exists()){//文件不存在 file1.createNewFile(); System.out.println("创建成功"); }else{//文件存在 file1.delete(); System.out.println("删除成

  • 浅谈Java多线程实现及同步互斥通讯

    Java多线程深入理解本文主要从三个方面了解和掌握多线程: 1. 多线程的实现方式,通过继承Thread类和通过实现Runnable接口的方式以及异同点. 2. 多线程的同步与互斥中synchronized的使用方法. 3. 多线程的通讯中的notify(),notifyAll(),及wait(),的使用方法,以及简单的生成者和消费者的代码实现. 下面来具体的讲解Java中的多线程: 一:多线程的实现方式 通过继承Threa类来实现多线程主要分为以下三步: 第一步:继承 Thread,实现Thr

  • 浅谈Java中常用数据结构的实现类 Collection和Map

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类. Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap Collection接口 Collection是最基本的集合接口,一个C

  • 浅谈Java中各种修饰符与访问修饰符的说明

    JAVA中的类只能是public 或者package的.这是符合逻辑的:人们定义类的初衷就是为了让别人用的.倘若是private,别人怎么调用?但是有一个内部类可以被定义为private.严格上说,内部类,算不得上是一种光明正大的类,内部类在某种意义上是类这个王国里的特务和地下工作者.特务和地下工作者为王国起了不少作用,但是几乎从来不敢在公众场合抛投露面.就算要露面,也要在主人(class)的同意下,向导(Interface)的引导下,才敢战战兢兢的走出来.下面是常规的一些类的修饰符和访问修饰符

随机推荐