关于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等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它 ...
随机推荐
- noip模拟29
这次终于是早上考试了 早上考试手感不错,这次刷新了以前的最高排名- %%%cyh巨佬 \(rk1\) %%%CT巨佬 \(t2\) 90 纵观前几,似乎我 \(t3\) 是最低的-- 总计挂分10分, ...
- Git 系列教程(6)- 查看 commit 提交历史
查看提交历史 在提交了若干更新,又或者克隆了某个项目之后,如何查看提交历史 git log 官方栗子 运行下面的命令获取该项目: git clone https://github.com/scha 运 ...
- Selenium系列4-元素定位
前言 说起元素定位,一定是学习自动化测试绕不开的第一道关,无论是web端的UI自动化还是移动端的自动化,在需要首先对元素进行定位才可以完成对元素的操作已达成测试目的,在Selenium中,可以使用fi ...
- WPF 通过进程实现异常隔离的客户端
当 WPF 客户端需要实现插件系统的时候,一般可以基于容器或者进程来实现.如果需要对外部插件实现异常隔离,那么只能使用子进程来加载插件,这样插件如果抛出异常,也不会影响到主进程.WPF 元素无法跨进程 ...
- Java环境搭建与HelloWprld—改变世界的第一步
1. JDK下载 访问oracle官网:http://www.oracle.com 在首页点击Downloads,进入oracle软件下载页. 在下载页面,点击Java. 选择Java (JDK) f ...
- PHP中的MySQLi扩展学习(一)MySQLi介绍
关于 PDO 的学习我们告一段落,从这篇文章开始,我们继续学习另外一个 MySQL 扩展,也就是除了 PDO 之外的最核心的 MySQLi 扩展.可以说它的祖先,也就是 MySQL(原始) 扩展是我们 ...
- centos8安装php扩展memcached报错
在php扩展memcached中执行./configure --with-php-config=/usr/local/php/bin/php-config 报错: error: memcached s ...
- 织梦 arclist调用副栏目内容解决办法
1 打开include/taglib/arclist.lib.php,找到296行: if($CrossID=='') $orwheres[] = ' arc.typeid IN ('.GetSonI ...
- Feign超时不生效问题
使用Feign作为RPC调用组件,可以配置连接超时和读取超时两个参数 使用Feign配置超时需要注意:Feign内部使用了负载均衡组件Ribbon,而Ribbon本身也有连接超时和读取超时相关配置一. ...
- 查看Docker启动jenkins的管理员密码
Docker启动docker后,第一次方法jenkins,需要输入管理员密码. 其实查看启动时候的日志可以看到密码,也可以按照以下方法找到密码. 1.查看docker容器ID:docker ps -a ...