阻塞IO实战与总结
2020-06-18 本文已影响0人
奋斗的韭菜汪
使用场景:在并发量低的情况下是适用的。
image.png
服务端:
public class SocketServerDemo {
public static void main(String[] args) {
ServerSocket serverSocket = null;
BufferedReader in = null;
BufferedWriter out = null;
try {
//监听8080端口
serverSocket = new ServerSocket(8080);
//阻塞等待客户端连接(连接阻塞)
Socket socket = serverSocket.accept();
//通过InputStream()接收数据
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("接收到客户端的消息 : " + in.readLine());
//写回去,通过OutputStream()发送数据
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//通过\n告诉接收端消息发送结束
out.write("服务端回复的消息\n");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
out.close();
in.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
public class SocketClientDemo {
public static void main(String[] args) {
Socket socket = null;
BufferedReader in = null;
BufferedWriter out = null;
try {
socket = new Socket("localhost", 8080);
//在这里睡眠100秒,当前客户端启动会IO阻塞在当前位置,如果服务端是单线程处
//理,启动第二个不睡眠的socketClient(自身不阻塞),第二个也会阻塞在第一个后面
//如何解决这个问题:可以在服务端开辟多个线程同时处理来自不同客户端的socket连接
Thread.sleep(100000);
//发送消息到服务端
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//通过\n告诉接收端消息发送结束
out.write("我是客户端发送了一个消息\n");
out.flush();
//接收来自服务端的消息
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("来自服务端的消息:" + in.readLine());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
try {
in.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
如何解决服务同时处理多个socketClient时IO阻塞问题:可以在服务端开辟多个线程同时处理来自不同客户端的socket连接
服务端优化代码如下:
服务端
public class SocketThread implements Runnable {
private Socket socket;
public SocketThread(Socket socket) {
this.socket = socket;
}
public void run() {
BufferedReader in = null;
BufferedWriter out = null;
try {
//通过InputStream()接收数据
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("接收到客户端的消息 : " + in.readLine());
//写回去,通过OutputStream()发送数据
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//通过\n告诉接收端消息发送结束
out.write("服务端回复的消息\n");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class SocketServer {
static ExecutorService executorService = newFixedThreadPool(20);
public static void main(String[] args) {
ServerSocket serverSocket = null;
//监听8080端口
try {
serverSocket = new ServerSocket(8080);
while (true){
Socket socket = serverSocket.accept();
//异步
executorService.execute(new SocketThread(socket));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
总结:上面虽然优化了IO 的处理方式,但是,不管是线程池还是单个线程,线程本身的处理个数是有限制的,对于操作系统来说,如果线程数太多会造成 CPU 上下文切换的开销。因此这种方式在高并发场景下不能解决根本问题,所以引入了非阻塞io
非阻塞io:https://www.jianshu.com/p/f510084d1a3b