下面是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();
}
}
}
}
【客户端代码】
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();
}
}
}
}
会一次性把所有数据读取到字节数组中去而且一个个字节读取这种方式 经常会出现一些莫名的问题把所有的数据读取到字节数组中最保险,
因为可能有些特殊的 比如 回车 换行符号 结束符号等 不好处理
你不是读取文件,所以这个条件不成立。,可以自己规定结束规则。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个字节。
都丫的是阻塞的。个人理解,欢迎拍砖!
你不是读取文件,所以这个条件不成立不是文件的结尾,是流的结尾,和读不读文件没有关系
从输入流读取下一个数据字节。返回 0 到 255 范围内的 int 字节值。如果因已到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流的末尾或者抛出异常前,此方法一直阻塞。
你的流根本就没有到达结尾,read()方法一直阻塞,怎么会返回-1呢?
socket和文件不一样,你从文件中读,读到末尾就到达流的结尾了,所以会返回-1,循环结束
socket如果不关闭的话,你的input会一直等待它发送数据,一直在等,就是所谓的阻塞了。所以整个程序都阻塞了。
另外caofaping说的“read(byte[] b) 读取最大byte[]的大小的数据,
这里没有阻塞的原因是你只读取byte数组的数据,没有while(true)...”也说明白了为什么你用注释里面的代码不会阻塞的原因。
客户端的代码为什么不会阻塞?因为如果你在服务器端激活注释里面的代码之后,服务器发送一个消息之后就执行finally里面的代码关闭socket了,在客户端就是输入流已经到达结尾了,所以不会阻塞。如果你不用注释里面的代码,服务器端一直在阻塞的,客户端肯定也在阻塞等待。
说了这么多,不知道你明白没有
谁可以接受一下啊?我也蒙了
read(byte[] b)没有循环,执行一次不管到没到流的结尾,读到了多少个数据,这个方法就结束了,所以不会阻塞
我们知道Socket的底层通信,是面向二进制比特流的。
发送方可以把文本信息编码成二进制信息进行发送,
但是,接收方并不知道何时才能接收结束。
由于楼主在接收方采用的是阻塞读的方式,所以,不出意外的情况下,接收方会始终保持接收状态。我看了一下楼主的代码,服务端,两种颜色的注释,无论哪种方式,都应该被阻塞下去。
第一种,每次循环读一个字节,应该阻塞在字符串数据的接收之后(也在循环体内)。
第二种,由于创建了缓冲区,并且,字符串数据没有将缓冲区填满,所以,仍然保持阻塞状态。以上纯属个人认知。请大家指正。