Socket 通信中read方法阻塞接收的问题

news/2024/5/17 16:16:48 标签: socket, java, read 阻塞, 网络编程, TCP

客户端:

java">public class Client {
    public static void main(String[] args) throws IOException {
//        与服务器建立连接
        Socket socket = new Socket("localhost", 1234);
//        向服务器发送消息
        OutputStream os = socket.getOutputStream();
        os.write("hello,serve!".getBytes());
//        等待服务器返回消息
        InputStream is = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer,0,len);
        }
//        打印服务器发来的数据
        System.out.println(baos);
//        关闭资源
        baos.close();
        is.close();
        os.close();
        socket.close();

    }
}

服务器:

java">public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(1234);
//        等待连接 阻塞方法
        Socket client = serverSocket.accept();
        System.out.println("客户端成功建立连接,等待客户端发送信息...");
        InputStream is = client.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
//        读取信息
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer,0,len);
        }
//        打印客户端发来的数据
        System.out.println(baos);
//        向服务器返回消息
        OutputStream os = client.getOutputStream();
        os.write("hello,client!".getBytes());
//        关闭资源
        os.close();
        baos.close();
        is.close();
        client.close();
        serverSocket.close();

    }
}

测试方法和期待的现象:
先启动Server服务器,等待客户端的连接,然后启动Client客户端,向服务器发送hello,serve!,服务器接收到信息后,向客户端返回hello,client!

实际现象:
服务器未打印出客户端发送的信息,服务器和客户端被阻塞住

原因分析:
代码在Server类的read()方法中阻塞住,服务器一直等待接受客户端的数据,并不知道客户端的数据已经发送完毕,没有返回-1,查看API如下:
在这里插入图片描述
解决方法1:
调用shutdownOutput方法()方法关闭输出流,或者close()方法直接关闭socket,这两种方法都会使对端的read方法返回-1,代码继续向下执行,区别是socket.close() 会将socket关闭连接,如果服务器给客户端反馈信息,此时客户端是收不到的,而socket.shutdownOutput()是将输出流关闭,此时,如果服务器有信息反馈,则客户端是可以正常接收的,修改客户端代码如下:

java">public class Client {
    public static void main(String[] args) throws IOException {
//        与服务器建立连接
        Socket socket = new Socket("localhost", 1234);
//        向服务器发送消息
        OutputStream os = socket.getOutputStream();
        os.write("hello,serve!".getBytes());
//		  关闭输出流
        socket.shutdownOutput();
//        等待服务器返回消息
        InputStream is = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer,0,len);
        }
//        打印服务器发来的数据
        System.out.println(baos);
//        关闭资源
        baos.close();
        is.close();
        os.close();
        socket.close();
    }
}

解决方法2:
发送数据时,约定数据的首部固定字节数为数据长度。这样读取到这个长度的数据后,就不继续调用read方法

解决方法3:
发送数据时,最后输出 \n 或 \r 作为数据传输终符
修改代码如下:
客户端:

java">        os.write("hello,serve!".getBytes());
        os.write("\n".getBytes());

服务器:

java">        byte[] buffer = new byte[1024];
        StringBuilder sb = new StringBuilder();
        int len;
//        读取信息
        while ((len=is.read(buffer)) != -1) {
            String s = new String(buffer, 0, len);
            if (s.equals("\n")) {
                break;
            }
            sb.append(s);
        }
//        打印客户端发来的数据
        System.out.println(sb);

参考文章:
https://www.cnblogs.com/gaoqiri/p/10055610.html
https://www.jianshu.com/p/cde27461c226
https://wiki.jikexueyuan.com/project/java-socket/socket-read-deadlock.html


http://www.niftyadmin.cn/n/1569926.html

相关文章

python许可证过期_x-pack许可证过期问题解决

原来安装一套elk日志系统,其中es和kibana用到x-pack插件,安装后可以免费试用一个月。一个月后需要许可证,一旦许可证过期将无法使用其中一些功能这一点官网有介绍:错误类型状态如下[rootxjjh-test1 ~]curl -u elastic:changeme 19…

数据库连接池被快速耗尽的一种可能原因

在环境中,出现了连接池连接耗尽,重启后也会快速再次被耗尽; 通过详细分析,发现存在一段代码存在手动开启事务,但是在某些条件下,会执行continue 导致提前执行完代码,未对事务进行提交或者回滚&a…

visual studio 没有属性页_在没有安装MATLAB的电脑上运行MATLAB程序

概述最近由于某种需求,需要在没有安装MATLAB的电脑B上运行MATLAB编写的程序,且电脑B上没有安装软件的权限!度娘上查了很多办法,基本上都是:1、先在有MATLAB的电脑上把程序编译成exe可执行文件,2、编译在电脑…

MySQL学习笔记(三)——DML语言

文章目录一.插入二.修改三.删除DML-Data Manipulate Language 数据操作语言一.插入 1.方式一: insert into 表名(字段名,...) values(值...);特点: 1.要求值的类型和字段的类型要一致或兼容 2.字段的个数和顺序不一定与原始表中的字段个数和顺序一致,但必须保证值和字段一 一…

国二python报名时间_2018年下半年全国计算机等级考试(NCRE)报名通知

2018年下半年全国计算机等级考试(以下简称NCRE)将于9月份举行,现就报名工作有关事项通知如下:一、考试时间、级别及科目2018年下半年NCRE时间为9月15日-17日,具体考试时间以准考证为准,开考级别、科目见附件1、2。二、报名事项说明…

MySQL学习笔记(四)——DDL语言

文章目录一.库的管理二.表的管理三.数据类型四.常见的约束1.创建表时添加约束2.修改表时添加或删除约束DDL-Data Define Languge 数据定义语言一.库的管理 1.创建库 create database 【if not exists】 库名【 character set 字符集名】;2.修改库 alter database 库名 chara…

w7设置双显示器_无损4K 144Hz?游戏大神狂赞的华硕DSC电竞显示器究竟是何方神圣...

在刚刚过去的2019年游戏圈,“肝”这个词相信玩家们绝对不会陌生。随着3A游戏大作《只狼:影逝二度》的发售,游戏圈便掀起了一波“肝”的风潮(当然,还有“死”……)。这是玩家们对于游戏征服欲的体现,也是对待优质作品的…

MySQL学习笔记(五)——TCL语言

文章目录事务一.含义二.特点(ACID)三.事务的使用步骤四.并发事务TCL-Transaction Control Language 事务控制语言事务 一.含义 事务:一条或多条sql语句组成一个执行单位,一组sql语句要么都执行要么都不执行 二.特点&#xff08…