关于Java Socket从输入流中read时阻塞

haobinbin 2010-12-16 09:25:44
下面是Socket客户端的源码,红色字体部分:将从服务端收到的反馈内容以read()方法输出,当读到最后一个字节时不会受到阻塞。而服务端的代码就不一样了。
【客户端代码】
public class SocketMain {

public static void main(String[] args) {
Socket socket = null;

OutputStream output = null;
InputStream input = null;

int read;
ByteArrayOutputStream byteOutput = null;
String result = null;

try {
socket = new Socket("localhost", 8888);

output = socket.getOutputStream();
input = socket.getInputStream();

// - 请求
output.write("这里是CSDN论坛!".getBytes());
output.flush();

byteOutput = new ByteArrayOutputStream();
while((read = input.read()) != -1){
byteOutput.write(read);
}


// - 响应
result = new String(byteOutput.toByteArray(),"GBK");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(output != null){
output.close();
}
if(input != null){
input.close();
}
if(byteOutput != null){
byteOutput.close();
}
if(socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

System.out.println(result);
}
}


下面是服务端代码,使用红色字体部分代码,当读到输入流中最后一个字节时会阻塞;如注释掉红色代码,解开蓝色代码的注释,就不会出现阻塞。请问这是什么原因??
【服务端代码】
public class ServerSocketMain {

public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;

OutputStream output = null;
InputStream input = null;

ByteArrayOutputStream byteOutput = null;

int read = 0;
String result = null;
byte[] bytes = null;

try {
serverSocket = new ServerSocket(8888);
while(true){
/*
* 循环内收到一个请求并处理完之后,必须将socket和output和input关掉,
* 下次收到请求时,再打开一个socket、output和input
*/
try{
socket = serverSocket.accept();

output = socket.getOutputStream();
input = socket.getInputStream();

// - 接收
byteOutput = new ByteArrayOutputStream();
int i=0;
while(true){
i++;
read = input.read();
System.out.println(read);
if(i > 100){
break;
}
byteOutput.write(read);
}
result = new String(byteOutput.toByteArray(), "GBK");


// bytes = new byte[1000];
// input.read(bytes);
// result = new String(bytes, "GBK");


System.out.println(result);

// - 反馈
output.write("郝彬彬先生,您好!".getBytes());
output.flush();
} catch (IOException e){
e.printStackTrace();
} finally {
try {
if(output != null){
output.close();
}
if(input != null){
input.close();
}
if(byteOutput != null){
byteOutput.close();
}
if(socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(serverSocket != null){
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
...全文
2775 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
haobinbin 2010-12-23
  • 打赏
  • 举报
回复
感谢大家发言,我现在似乎有点明白了。
修行者1988 2010-12-23
  • 打赏
  • 举报
回复
我看了下,应该是if(i>100)...那儿出了问题,如果客户端发的请求没有一百个字节那么你那段代码就是死循环,服务器就在那儿不停的读,但是又读不到,所以堵塞了···


bosi1221 2010-12-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 chj97 的回复:]

6楼,我也有点问题,如果“read(byte[] b)” 读取最大byte[]的大小的数据,不会阻塞,那么1楼的也最多读取100次啊,也不应该阻塞啊?而且“read(byte[] b)”中读取到实际大小后也没有数据可以读了啊,也得等客户端输入,也得阻塞啊?
谁可以接受一下啊?我也蒙了
[/Quote]
首先,原先的代码因为有100次的循环,其实如果读取的字节数没有100,比如只有16个,那么循环16次之后read()方法就阻塞在那里了。
read(byte[] b)没有循环,执行一次不管到没到流的结尾,读到了多少个数据,这个方法就结束了,所以不会阻塞
冰思雨 2010-12-18
  • 打赏
  • 举报
回复
楼主,客户端C向服务端S发送信息,服务端通过什么方式才能知道,客户端C发送信息已经结束?
我们知道Socket的底层通信,是面向二进制比特流的。
发送方可以把文本信息编码成二进制信息进行发送,
但是,接收方并不知道何时才能接收结束。
由于楼主在接收方采用的是阻塞读的方式,所以,不出意外的情况下,接收方会始终保持接收状态。

我看了一下楼主的代码,服务端,两种颜色的注释,无论哪种方式,都应该被阻塞下去。
第一种,每次循环读一个字节,应该阻塞在字符串数据的接收之后(也在循环体内)。
第二种,由于创建了缓冲区,并且,字符串数据没有将缓冲区填满,所以,仍然保持阻塞状态。

以上纯属个人认知。请大家指正。
jianjian168 2010-12-18
  • 打赏
  • 举报
回复
用线程解决,我也不清楚
bosi1221 2010-12-17
  • 打赏
  • 举报
回复 1
首先,你要仔细看明白read()方法的介绍:
从输入流读取下一个数据字节。返回 0 到 255 范围内的 int 字节值。如果因已到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流的末尾或者抛出异常前,此方法一直阻塞。
你的流根本就没有到达结尾,read()方法一直阻塞,怎么会返回-1呢?
socket和文件不一样,你从文件中读,读到末尾就到达流的结尾了,所以会返回-1,循环结束
socket如果不关闭的话,你的input会一直等待它发送数据,一直在等,就是所谓的阻塞了。所以整个程序都阻塞了。
另外caofaping说的“read(byte[] b) 读取最大byte[]的大小的数据,
这里没有阻塞的原因是你只读取byte数组的数据,没有while(true)...”也说明白了为什么你用注释里面的代码不会阻塞的原因。
客户端的代码为什么不会阻塞?因为如果你在服务器端激活注释里面的代码之后,服务器发送一个消息之后就执行finally里面的代码关闭socket了,在客户端就是输入流已经到达结尾了,所以不会阻塞。如果你不用注释里面的代码,服务器端一直在阻塞的,客户端肯定也在阻塞等待。
说了这么多,不知道你明白没有
juaner 2010-12-17
  • 打赏
  • 举报
回复
谁可以解释一下啊?
juaner 2010-12-17
  • 打赏
  • 举报
回复
6楼,我也有点问题,如果“read(byte[] b)” 读取最大byte[]的大小的数据,不会阻塞,那么1楼的也最多读取100次啊,也不应该阻塞啊?而且“read(byte[] b)”中读取到实际大小后也没有数据可以读了啊,也得等客户端输入,也得阻塞啊?
谁可以接受一下啊?我也蒙了
caofaping 2010-12-16
  • 打赏
  • 举报
回复
read() 如果已到达文件末尾,则返回 -1,
你不是读取文件,所以这个条件不成立。,可以自己规定结束规则。

read(byte[] b) 读取最大byte[]的大小的数据,
这里没有阻塞的原因是你只读取byte数组的数据,没有while(true),你怎么就知道byte[]就能读取你所有的内容。
你是直接byte[1000],你writer的字节数少于1000,如果你改下下面的代码。


while(true){
read = input.read(bytes);
if(read == -1){
break;
}
result = new String(bytes, "GBK");
System.out.println(result);
}


你发现和read()一样
read()和read(byte[])区别在于前者一次读取一个字节,后者一次最多读取byte个字节。
都丫的是阻塞的。

个人理解,欢迎拍砖!
haobinbin 2010-12-16
  • 打赏
  • 举报
回复
可read()方法,在输入流中没有字节之后不就返回-1吗?为啥没返回反而是阻塞程序运行了呢?
m_ting 2010-12-16
  • 打赏
  • 举报
回复
呵呵~~~~~~~~~~~~~~~
Jlins 2010-12-16
  • 打赏
  • 举报
回复
input.read(bytes);
会一次性把所有数据读取到字节数组中去

而且一个个字节读取这种方式 经常会出现一些莫名的问题

把所有的数据读取到字节数组中最保险,
因为可能有些特殊的 比如 回车 换行符号 结束符号等 不好处理
bosi1221 2010-12-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 caofaping 的回复:]

read() 如果已到达文件末尾,则返回 -1,
你不是读取文件,所以这个条件不成立。,可以自己规定结束规则。

read(byte[] b) 读取最大byte[]的大小的数据,
这里没有阻塞的原因是你只读取byte数组的数据,没有while(true),你怎么就知道byte[]就能读取你所有的内容。
你是直接byte[1000],你writer的字节数少于1000,如果你改下下面的代……
[/Quote]
read() 如果已到达文件末尾,则返回 -1,
你不是读取文件,所以这个条件不成立

不是文件的结尾,是流的结尾,和读不读文件没有关系

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧