服务器BIO通讯模型:
采用BIO通信模型的服务器端,通常是有一个专门负责监听客户端键入的的一个线程,一般叫它为Acceptor 线程。当Acceptor 线程接收到客户端的连接请求后,它就为每个客户端创建一个新的线程来进行链路处理,处理完后,通过输出流返回给客户端,然后线程就销魂掉了,一般我们称这种模型为One Request VS One Response. 一般的结构图如下:
这个模型的弊端:如果客户端接入量不大,在服务器承压范围内,这个模型也可以用,但是如果客户端的并发访问量不断增多,服务端线程和客户端的数量保存1:1的比例,那么客户端每增加一个,服务器就的创建一个线程来处理相关的业务。因为服务器创建线程要不断的消耗服务器资源,导致系统资源不断的消耗,性能不断下滑,当线程创建到一定数据量以后,再创建线程就会失败,其他的业务处理也会导致失败,最终服务器进程崩溃,无法处理对应的业务。下面我们将BIO通信模型的代码贴上,希望读者从中受益。
服务端代码如下:
package com.tlc.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class BioGetNameServer {
private static final int PORT = 8080;
public static final String NAME_1 = “A”;
public static final String NAME_2 = “B”;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(PORT);
Socket socket = null;
//主线程不断的轮询客户端连接请求
while (true) {
//一直阻塞等待客户的连接,连接成功以后返回一个socket,通过这个socket来跟客户端通信
System.out.println(“start server”);
socket = serverSocket.accept();
System.out.println(“have a client connect server”);
//为每个客户端创建一个单独线程来处理具体的业务
new Thread(new HandlerClientRunnable(socket)).start();
}
} finally {
//当服务器异常退出的时候,释放相应的资源
if (serverSocket != null) {
serverSocket.close();
serverSocket = null;
}
}
}
static class HandlerClientRunnable implements Runnable {
private Socket socket;
public HandlerClientRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
//包装socket的输入流
in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
//包装socket的输出流
out = new PrintWriter(this.socket.getOutputStream(),true);
String content = null;
while (true) {
//不断的读取客户端发送过来的数据
System.out.println(“read client send content”);
content = in.readLine();
//如果读到的数据为空,就继续读
if (content == null) {
System.out.println(“read client send content is null “);
break;
}
System.out.println(“read client send content: “+content);
//如果读到数据是NAME_1
if (content.equalsIgnoreCase(NAME_1)) {
out.println(“Hello ” + NAME_1 + ” ” + new Date(System.currentTimeMillis()));
} else {
out.println(“Hello ” + NAME_2 + ” ” + new Date(System.currentTimeMillis()));
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//先关闭socket的输入流
if (in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
e.printStackTrace();
}
}
//先关闭socket的输出流
if (out != null) {
out.close();
out = null;
}
//关闭socket
if (socket != null) {
try {
socket.close();
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
客户端代码如下:
import com.tlc.server.BioGetNameServer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class BioGetNameClient {
private static final int PORT = 8080;
private static final String IP = “127.0.0.1”;
public static void main(String[] args) {
BufferedReader in = null;
PrintWriter out = null;
Socket socket = null;
try {
socket = new Socket(IP, PORT);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
//发送查询给服务器
out.println(BioGetNameServer.NAME_1);
//马上读取服务器的回复
String respone = in.readLine();
System.out.println(“Server replay:” + respone);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
out = null;
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
}
}
}
从上面的模型到代码实现,很容易发现BIO这架构,无法满足高性能,高并发服务器的结构,那么接下来我们改造一下这种一对一的架构。
Java Socket & Java NIO 编程解析
最新推荐文章于 2021-08-20 17:43:20 发布