BIO通信模型
BIO通信服务端,通常有一个独立的Acceptor线程负责监听客户端的连接。接收到客户端连接请求后会为每个客户端创建一个新的线程进行链路处理,处理完成后返回应答给客户端,也就是经典的请求-应答通信模型。但是随着客户端并发量上升,服务端的线程数膨胀,系统性能急剧下降,最终会导致系统不可用。
Server端代码:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by hao.g on 18/5/7.
*/
public class BioServer {
public static void main(String[] args) {
int port = 9090;
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
while (true){
//如果没有客户端连接则阻塞
Socket socket = serverSocket.accept();
new Thread(new BioHandler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (serverSocket != null){
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.net.Socket;
/**
* Created by hao.g on 18/5/7.
*/
public class BioHandler implements Runnable{
private Socket socket;
public BioHandler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
System.out.println(socket.toString());
}
}
如果没有客户端接入,代码会一直阻塞在
Socket socket = serverSocket.accept();
启动server端,通过命令jstack pid观察线程堆栈信息,主程序确实阻塞在accept方法上
当有客户端接入时,服务端新建一个线程处理BioHandler,打印客户端socket相关信息。
Client端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* Created by hao.g on 18/5/7.
*/
public class BioClient {
public static void main(String[] args) {
String host = "127.0.0.1";
int port = 9090;
Socket socket = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
可见每次有新的连接时,服务端都会创建新的线程。这种模型无法满足高并发,高性能的场景。