想用Socket写一个Server端和Client端一个请求回复的Demo 发现程序阻塞了 记录一下
我是这么写的
public class BioClient1 {
public static void main(String[] args) throws IOException {
Socket socket = null;
try {
//发送你好
socket = new Socket("127.0.0.1", 8080);
OutputStream outputStream = socket.getOutputStream();
BufferedOutputStream dos = new BufferedOutputStream(outputStream);
dos.write("你好啊".getBytes());
dos.flush();
//接收服务端返回数据
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int offset = -1;
byte[] buffer = new byte[1024];
while ((offset = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, offset);
}
inputStream.close();
System.out.println(byteArrayOutputStream);
byteArrayOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
}
public class BioServer1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
for(;;) {
Socket accept = serverSocket.accept();
SocketHandle socketHandle = new SocketHandle(accept);
socketHandle.start();
}
}
static class SocketHandle extends Thread {
private Socket socket;
SocketHandle(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int offset = -1;
//如果用这个的话这行代码的read方法会阻塞 因为客户端的OutputStream没有关闭
while ((offset = inputStream.read(bytes)) != -1) {
baos.write(bytes, 0, offset);
}
byte[] result = new byte[read];
System.arraycopy(bytes, 0, result, 0, read);
System.out.println(new String(result, StandardCharsets.UTF_8));
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你也好啊".getBytes());
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
整个流程大概是
阻塞问题出现在Server端的inputStream.read()中 这个是因为客户端的outputStream发送完消息后并没有close 因为我之后还要用到客户端的inputStream获取服务端回复的消息 如果客户端发送完消息就关闭outputStream 之后获取inputStream会报连接重置异常 所以这边给出两种方案
1.只修改服务端只调用一次 inputStream.read 这样就不会阻塞了 但只能获取不能大于的数组大小的字符了
public class BioServer1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
for(;;) {
Socket accept = serverSocket.accept();
SocketHandle socketHandle = new SocketHandle(accept);
socketHandle.start();
}
}
static class SocketHandle extends Thread {
private Socket socket;
SocketHandle(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
byte[] result = new byte[read];
System.arraycopy(bytes, 0, result, 0, read);
System.out.println(new String(result, StandardCharsets.UTF_8));
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你也好啊".getBytes());
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
客户端的代码不用修改 但如果把服务端中的最后的socket.close和outputStream.close();去掉的话 客户端依旧会阻塞
2.在客户端发送信息完成之后调用socket的shutdownOutput方法 这个就只需要修改客户端的代码
public class BioClient1 {
public static void main(String[] args) throws IOException {
Socket socket = null;
try {
//发送你好
socket = new Socket("127.0.0.1", 8080);
OutputStream outputStream = socket.getOutputStream();
BufferedOutputStream dos = new BufferedOutputStream(outputStream);
dos.write("你好啊".getBytes());
dos.flush();
//添加关闭socket 输出流
socket.shutdownOutput();
//接收服务端返回数据
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int offset = -1;
byte[] buffer = new byte[1024];
while ((offset = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, offset);
}
inputStream.close();
System.out.println(byteArrayOutputStream);
byteArrayOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
}
这个方法相对优雅
相关阅读
记录一次Socket的异常:InputStream.read()阻塞问题_鸡冠花12138的博客-CSDN博客_inputstream read 超时