这两天没事学习的时候,看到了一个boi的一个例子,自己按照教程编写的时候,发现怎么运行都不成功,客户端一直被阻塞在读的地方,debug也没有查到问题的关键,后来找了很多地方,也没有看到太好的解释。后来就看api发现了两个方法,测试了一下,发现好用了。
简要介绍一下案例
我的客户端发送一个时间给服务端,然后服务端接收这个数据并给客户端返回一个数据,然后客户端接收这个数据并输出。
我在实现这个功能的时候,发现客户端和服务端启动后都被阻塞住了,原因是当客户端给服务端发送完数据的时候服务端在读取数据,但是服务端没有办法判断什么时候会自动中断,所以他会在这个地方阻塞。阻塞之后服务端就没有办法往客户端发送数据,这个时候客户端的接收数据也会等服务端的数据,会在这里阻塞。这个时候服务端和客户端都不会关闭,会一直持续阻塞。
造成这个问题一共有两个原因,
第一传递数据的时候,另一端不知道什么时候终止,用read!=-1是没有办法判断出来的,因为流没有终止,流一直存在,所以另一端以为数据没有传输完毕。
第二,如果数据量不够大的话,就会造成数据被写入内存,而没有被传输过去,只是被放到了内存。
解决这两个问题,第一个在你传输的时候随时记得刷新一下flush()或者使用一些会自动刷新的写的方法如println();第二个问题就是,在传输结束之后,你可以把流进行关闭,使用socket.shutdownOutput()和socket.shutdownInput()这两个方法,将流关闭掉,对面就可以接收到结束的信号。
我的代码如下你们可以用我这个代码进行测试,关键地方我可以删除那几条测试看看有什么反应。
server端
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* server运行
* @author pg
*/
public class TimeService {
public static void main(String[] args) {
int port = 12345;
ServerSocket server = null;
try {
server = new ServerSocket(port);
while(true){
Socket accept = server.accept();
new Thread(new RunableTimeService(accept)).start();;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(server!=null){
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端线程的实现方法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
public class RunableTimeService implements Runnable {
private Socket socket;
public RunableTimeService(Socket accept) {
socket = accept;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String body = null;
while(true){body = in.readLine();
if(body==null)
break;
System.out.println("in "+body);
}
//关闭输入的流
socket.shutdownInput();
//使用println输出,带有自动刷新的功能
out.println("server out put "+new Date().getTime());
//关闭输出的流
socket.shutdownOutput();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
client端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
/**
* client运行
* @author pg
*
*/
public class TimeClient {
public static void main(String[] args) {
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
try {
socket = new Socket("127.0.0.1", 12345);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
//输出一个时间
out.write("client "+new Date().getTime());
//刷新输出的数据
out.flush();
//关闭输出的流
socket.shutdownOutput();
while(true){
String body = in.readLine();
if(body==null)
break;
System.out.println("server time is + "+body);
}
//关闭输入的流
socket.shutdownInput();
}catch (IOException e) {
e.printStackTrace();
}finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
如有问题 谢谢更正