java tcp read_【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...
书上示例
在第一章《基本套接字》中,作者给出了一个TCP Socket通信的例子——反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去。
书上客户端代码如下:
书上的服务器端代码如下:
示例程序当然运行无误,运行结果如下:
问题的引出
首先明确几点:
1、客户端与服务器端在接收和发送数据时,read()和write()方法不一定要对应,比如,其中一方可以一次发送多个字节的数据,而另一方可以一个字节一个字节地接收,也可以一个字节一个字节地方送,而多个字节多个字节地接收。因为TCP协议会将数据分成多个块进行发送,而后在另一端会从多个块进行接收,再组合在一起,它并不仅能确定read()和write()方法中所发送信息的界限。
2、read()方法会在没有数据可读时发生阻塞,直到有新的数据可读。
注意客户端中下面部分代码
客户端从Socket套接字中读取数据,直到收到的数据的字节长度和原来发送的数据的字节长度相同为止,这里的前提是已经知道了要从服务器端接收的数据的大小,如果现在我们不知道要反馈回来的数据的大小,那么我们只能用read方法不断读取,直到read()返回-1,说明接收到了所有的数据。我这里采用一个字节一个字节读取的方式,代码改为如下:
这时问题就来了,输出结果如下:
问题的分析
客户端没有数据打印出来,初步推断应该是read()方法始终没有返回-1,导致程序一直无法往下运行,我在客客户端执行窗口中按下CTRL+C,强制结束运行,在服务器端抛出如下异常:
Exception in thread “main” java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at TCPEchoServer.main(TCPEchoServer.java:32)
异常显示,问题出现在服务端的32行,没有资源可读,现在很有可能便是由于read()方法始终没有返回-1所致,为了验证,我在客户端读取字节的代码中加入了一行打印读取的单个 字符的代码,如下:
此时运行结果如下:
很明显,客户端程序在打印出最有一个字节后不再往下执行,没有执行其后面的System.out.println(“Received: ” + new String(data));这行代码,这是因为read()方法已经将数据读完,没有数据可读,但又没有返回-1,因此在此处产生了阻塞。这便造成了TCP Socket 通信的死锁问题。
问题的解决
查阅相关资料,仔细阅读了书上的每个细节,在通过对比书上的代码和自己的代码,发现了问题所在。问题就出现在read()方法上,这里的重点是read()方法何时返回-1,在一般的文件读取中,这代表流的结束,亦即读取到了文件的末尾,但是在Socket套接字中,这样的概念很模糊,因为套接字中数据的末尾并没有所谓的结束标记,无法通过其自身表示传输的数据已经结束,那么究竟什么时候read()会返回-1呢?答案是:当TCP通信连接的一方关闭了套接字时。
再次分析改过后的代码,客户端用到了read()返回-1这个条件,而服务端也用到了,只有二者有一方关闭了Socket,另一方的read()方法才会返回-1,而在客户端打印输出前,二者都没有关闭Socket,因此,二者的read()方法都不会返回-1,程序便阻塞在此处,都不往下执行,这便造成了死锁。
反过来,再看书上的给出的代码,在客户端代码的while循环中,我们的条件是totalBytesRcvd < data.length,而不是(bytesRcvd = in.read())!= -1,这样,客户端在收到与其发送相同的字节数之后便会退出while循环,再往下执行,便是关闭套接字,此时服务端的read()方法检测到客户端的关闭,便会返回-1,从而继续往下执行,也将套接字关闭。因此,不会产生死锁。
那么,如果在客户端不知道反馈回来的数据的情况下,该如何避免死锁呢?Java的Socket类提供了shutdownOutput()和shutdownInput()另个方法,用来分别只关闭Socket的输出流和输入流,而不影响其对应的输入流和输出流,那么我们便可以在客户端发送完数据后,调用shutdownOutput()方法将套接字的输出流关闭,这样,服务端的read()方法便会返回-1,继续往下执行,最后关闭服务端的套接字,而后客户端的read()方法也会返回-1,继续往下执行,直到关闭套接字。
客户端改变后的代码部分如下:
这样,便得到了预期的运行结果,如下:
总结
由于read()方法只有在另一端关闭套接字的输出流时,才会返回-1,而有时候由于我们不知道所要接收数据的大小,因此不得不用read()方法返回-1这一判断条件,那么此时,合理的程序设计应该是先关闭网络输出流(亦即套接字的输出流),再关闭套接字。
http://www.importnew.com/20151.html
java tcp read_【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...相关推荐
- 【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...
书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 1 2 3 ...
- java 参数返回_Java基础---Java中带参数返回值方法的使用(四十)
Java 中带参带返回值方法的使用 如果方法既包含参数,又带有返回值,我们称为带参带返回值的方法. 例如:下面的代码,定义了一个 show 方法,带有一个参数 name ,方法执行后返回一个 Stri ...
- java后台传一个对象到前台_前台判断对象中的一个布尔值_springMVC面试题
1:springMVC工作原理 springMVC架构.png [用户发送请求到前端控制器dispatcherservlet,前端控制器接收到请求之后调用处理器映射器,根据请求url找到具体的处理器, ...
- JAVA中返回值为字母时_LeetCode#524通过删除字母匹配到字典里最长单词-java中CompareTo方法用法以及Comparator中Compare方法返回值...
import java.util.Collections; import java.util.Comparator; import java.util.List; /* 524. 通过删除字母匹配到字 ...
- Java基础---Java中带参数返回值方法的使用(四十)
Java 中带参带返回值方法的使用 如果方法既包含参数,又带有返回值,我们称为带参带返回值的方法. 例如:下面的代码,定义了一个 show 方法,带有一个参数 name ,方法执行后返回一个 Stri ...
- java return返回值_java中关于return返回值的用法详解
我们输入一个条件时,系统就会对这个条件进行判断,然后给出一个返回时的结论,我们把这个结果看做是返回值.在java里可以使用return语句来进行返回,从字面意思就能很好的理解它的用法了.下面我们就re ...
- java中怎么编写围棋对弈_java课程设计围棋对弈(含代码).doc
java课程设计围棋对弈(含代码).doc C:\ProgramFiles\Java\jdk1.8.0_45Java程序课程设计任务书1.主要任务与目标创建一个围棋对弈平台.基于Panel类定义一个面 ...
- java什么时候用有参_Java有陷阱——慎用入参做返回值
正常情况下,在Java中入参是不建议用做返回值的.除了造成代码不易理解.语义不清等问题外,可能还埋下了陷阱等你入坑. 问题背景 比如有这么一段代码: 上面代码,服务A希望调用服务B,以获取supply ...
- java中怎么表示数组中的某个值_简易Java(12):如何高效检查一个数组中是否包含某个值?...
如何检查一个数组(未排序)中是否包含某个特定的值?在Java中,这是一个非常有用并又很常用的操作.同时,在StackOverflow中,有时一个得票非常高的问题.在得票比较高的几个回答中,时间复杂度差 ...
最新文章
- 07.GitHub实战系列~7.Git之VS2013团队开发(如果不想了解git命令直接学这篇即可)...
- DotNetNuke安装与下载
- 从智能交通到智能能源:智慧城市在7个方面的应用实践
- 转:Bit-Map思想与2-BitMap思想
- vivado-SOC-----Memory内存测试和DDR测试(初学者SDK hello world不通的有救了~)
- 殷墟 太行山 红旗渠
- php 多图上传编辑器,ThinkPHP5整合LayUI编辑器图片上传
- LeetCode 123. 买卖股票的最佳时机 III(动态规划)
- ByteArrayOutputStream和ByteArrayInputStream的简单使用
- pytorch tensor 梯度
- angualrjs学习总结二(作用域、控制器、过滤器)
- 期货交易常用术语中英文对照表
- 这是一个没有现金的国家——丹麦
- 联想服务器装系统鼠标没反应,联想Thinkpad重装系统后键盘鼠标失灵的解决方法...
- 《码农翻身》各章节阅读链接
- Python爬虫实战(2)之爬取NBA球队各个球员头像图片
- 变换矩阵_平移 缩放 旋转及统一变换
- 基带传输中的信道编码和信源编码
- 英语“死”的委婉说法
- Android音频和视频开发