客户端:
public class Client {
public static void main(String[] args) throws IOException {
// 与服务器建立连接
Socket socket = new Socket("localhost", 1234);
// 向服务器发送消息
OutputStream os = socket.getOutputStream();
os.write("hello,serve!".getBytes());
// 等待服务器返回消息
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer,0,len);
}
// 打印服务器发来的数据
System.out.println(baos);
// 关闭资源
baos.close();
is.close();
os.close();
socket.close();
}
}
服务器:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(1234);
// 等待连接 阻塞方法
Socket client = serverSocket.accept();
System.out.println("客户端成功建立连接,等待客户端发送信息...");
InputStream is = client.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
// 读取信息
while ((len = is.read(buffer)) != -1) {
baos.write(buffer,0,len);
}
// 打印客户端发来的数据
System.out.println(baos);
// 向服务器返回消息
OutputStream os = client.getOutputStream();
os.write("hello,client!".getBytes());
// 关闭资源
os.close();
baos.close();
is.close();
client.close();
serverSocket.close();
}
}
测试方法和期待的现象:
先启动Server服务器,等待客户端的连接,然后启动Client客户端,向服务器发送hello,serve!
,服务器接收到信息后,向客户端返回hello,client!
实际现象:
服务器未打印出客户端发送的信息,服务器和客户端被阻塞住
原因分析:
代码在Server类的read()方法中阻塞住,服务器一直等待接受客户端的数据,并不知道客户端的数据已经发送完毕,没有返回-1,查看API如下:
解决方法1:
调用shutdownOutput方法()方法关闭输出流,或者close()方法直接关闭socket,这两种方法都会使对端的read方法返回-1,代码继续向下执行,区别是socket.close() 会将socket关闭连接,如果服务器给客户端反馈信息,此时客户端是收不到的,而socket.shutdownOutput()是将输出流关闭,此时,如果服务器有信息反馈,则客户端是可以正常接收的,修改客户端代码如下:
public class Client {
public static void main(String[] args) throws IOException {
// 与服务器建立连接
Socket socket = new Socket("localhost", 1234);
// 向服务器发送消息
OutputStream os = socket.getOutputStream();
os.write("hello,serve!".getBytes());
// 关闭输出流
socket.shutdownOutput();
// 等待服务器返回消息
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer,0,len);
}
// 打印服务器发来的数据
System.out.println(baos);
// 关闭资源
baos.close();
is.close();
os.close();
socket.close();
}
}
解决方法2:
发送数据时,约定数据的首部固定字节数为数据长度。这样读取到这个长度的数据后,就不继续调用read方法
解决方法3:
发送数据时,最后输出 \n 或 \r 作为数据传输终符
修改代码如下:
客户端:
os.write("hello,serve!".getBytes());
os.write("\n".getBytes());
服务器:
byte[] buffer = new byte[1024];
StringBuilder sb = new StringBuilder();
int len;
// 读取信息
while ((len=is.read(buffer)) != -1) {
String s = new String(buffer, 0, len);
if (s.equals("\n")) {
break;
}
sb.append(s);
}
// 打印客户端发来的数据
System.out.println(sb);
参考文章:
https://www.cnblogs.com/gaoqiri/p/10055610.html
https://www.jianshu.com/p/cde27461c226
https://wiki.jikexueyuan.com/project/java-socket/socket-read-deadlock.html