关于java socket中的read方法阻塞问题
客户端:
public class TCPClient {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("E:\\Trump.jpg");
Socket socket=new Socket("127.0.0.1",8888);
OutputStream os=socket.getOutputStream();
byte[] bytes=new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
//将读取到的数据传输到客户端与服务器端之间的IO流
os.write(bytes,0,len);
}
//读服务器回写的数据
InputStream is=socket.getInputStream();
len=is.read(bytes);
System.out.println(new String(bytes,0,len));
socket.close();
fis.close();
}
}
服务器端:
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(8888);
Socket socket=server.accept();
InputStream is=socket.getInputStream();
FileOutputStream fos=new FileOutputStream("E:\\Test\\Trump.jpg");
int len;
byte[] bytes=new byte[1024];
while ((len=is.read(bytes))!=-1) {
fos.write(bytes,0,len);
}
OutputStream os=socket.getOutputStream();
os.write("文件上传完毕!".getBytes());
fos.close();
socket.close();
}
}
这段代码执行以后会发现server类 read()方法发生了阻塞,经过查找资料发现read()是一个阻塞函数(阻塞函数就是当这个函数不执行完,函数所在线程就一直停止在这里不动。)。
在输入数据可用、检测到流末尾或者抛出异常前,read方法一直阻塞。如果客户端没有声明断开outputStream那么它就会认为客户端仍旧可能发送数据,像read()这种阻塞读取函数还有BufferedReader类种的 readLine()、DataInputStream种的readUTF()等。
解决方案:
Socket任意一端在调用完write()方法时调用shutdownOutput()方法关闭输出流,这样服务器端的inputStream上的read操作就会返回-1, 这里我们要注意下不能调用socket.getInputStream().close()。因为它会导致socket直接被关闭。 当然如果不需要继续在socket上进行读操作,也可以直接关闭socket。但是这个方法不能用于通信双方需要多次交互的情况。
原文:https://www.cnblogs.com/gaoqiri/p/10055610.html
关于java socket中的read方法阻塞问题的更多相关文章
- Java socket中关闭IO流后,发生什么事?(以关闭输出流为例)
声明:该博文以socket中,关闭输出流为例进行说明. 为了方便讲解,我们把DataOutputstream dout = new DataOutputStream(new BufferedOutpu ...
- 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)
编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...
- Java多线程中的join()方法
一.join()方法介绍 join() 定义在Thread.java中.join()方法把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的join( ...
- 模拟做饭系统(java+线程中的join方法)
(一)项目框架分析 妈妈要去做饭,发现没有酱油,让儿子去买酱油,然后回来做饭. 根据面向对象的思想,有两个对象,妈妈和儿子 主要有两个方法: (一)没有线程控制(即儿子没有买酱油回来妈妈就做好饭了)+ ...
- 关于Java JDK中 URLDecoder.decode 方法
java.net.URLDecoder.decode 在项目中碰到了个比较奇怪的问题,就是我在本地使用java.net.URLDecoder.decode(ruleName)方法解码,没有问题,本地的 ...
- java 多线程中的wait方法的详解
java多线程中的实现方式存在两种: 方式一:使用继承方式 例如: PersonTest extends Thread{ String name; public PersonTest(String n ...
- java——包装类中的equals方法
基本数据类型包装类中的equals方法用于比对相同包装类中的值是否相等,如果两者比较的包装类类型不同则返回false: Byte public boolean equals(Object obj) { ...
- Java 输出流中的flush方法
转自:http://blog.csdn.net/jiyangsb/article/details/50984440 java中的IO流中的输出流一般都有flush这个操作,这个操作的作用是强制将缓存中 ...
- 编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)
建议16:易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP,Ruby,Groovy.Javascript等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它 ...
随机推荐
- Intel® QAT加速卡之同步异步模式
QAT 的两种操作模式 Intel QAT API同时支持同步和异步两种操作模式. 为了获得最佳性能,该应用程序应能够向加速引擎提交多个未完成的请求. 提交多个未完成的请求可最大程度地减少加速引擎上的 ...
- @RequestParam、@RequestBody、@PathVariable区别和案例分析
一.前言 @RequestParam.@RequestBody.@PathVariable都是用于在Controller层接收前端传递的数据,他们之间的使用场景不太一样,今天来介绍一下!! 二.实体类 ...
- 【Git】给不同目录配置不同的用户名和邮箱
场景 使用 git 时,对于公司项目和个人项目想用不同的用户名和邮箱提交,简单的解决方式就是对 git 仓库单独配置 user.name 和 user.email: 直接修改当前仓库的 .git/co ...
- 30天自制操作系统(二)汇编语言学习和Makefile入门
我们继续学习操作系统的相关内容. ; hello-os ; TAB=4 ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのた ...
- ACID的实现原理
引言 ACID是事务的特点也是必须的要求,只有保证ACID事务的执行才不会出错,分别是原子性.一致性.隔离性和持久性.我们知道典型的MySQL事务是这样执行的: start transaction 开 ...
- vscode 本地启动配置
安装vscode 编辑器后,找到插件 1.安装Debugger for Chrome 2.找到本地需要启动的项目,配置文件,从左到右依次点击红圈中的按钮,然后出现launch.json文件,在里面添加 ...
- mysql 复合索引 为什么遵循最左原则
1,>mysql :多列索引 https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html 1>,B+树: h ...
- javascript 面向对象 模块
* module 完成函数 createModule,调用之后满足如下要求:1.返回一个对象2.对象的 greeting 属性值等于 str1, name 属性值等于 str23.对象存在一个 say ...
- django 常用教程网址
第一:url中反向解析教程网址 https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#url
- 版本管理 - Git 使用入门
Git 是一个分布式的版本管理系统,而 SVN 是一个集中式管理系统. 版本控制 Git与SVN的对比 对比 SVN Git 工作方式 集中式 分布式 文件管理 增量式 系统快照 权限控制 对团队中参 ...