One BIO Demo
2018-12-06 本文已影响3人
匠丶
本文将实现一个输入字符表达式,输出算术结果的BIO程序。通过该程序能进一步帮助理解什么是同步阻塞IO。
服务端
BIOServer,启动服务端,并循环监听客户端连接,每监听到一个请求,创建一个新线程处理数据。注意serverSocket.accept()方法,在未接收到连接时,会一直阻塞。
public class BIOServer {
//默认的端口号
private static int DEFAULT_PORT = 7777;
//单例的ServerSocket
private static ServerSocket serverSocket;
//根据传入参数设置监听端口,如果没有参数调用以下方法并使用默认值
public static void start() throws IOException {
//使用默认值
start(DEFAULT_PORT);
}
public synchronized static void start(int port) throws IOException {
if (serverSocket != null) return;
try {
//通过构造函数创建ServerSocket
//如果端口合法且空闲,服务端就监听成功
serverSocket = new ServerSocket(port);
System.out.println("服务端已启动,端口号:" + port);
//通过无线循环监听客户端连接
//如果没有客户端接入,将阻塞在accept操作上。
while (true) {
Socket socket = serverSocket.accept();
new Thread(new ServerHandler(socket)).start();
}
} finally {
//一些必要的清理工作
if (serverSocket != null) {
System.out.println("服务端已关闭。");
serverSocket.close();
serverSocket = null;
}
}
}
}
ServerHandler,线程处理数据流程。从输入流读数据,写数据到输出流。
public class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
String expression;
int result;
while (true) {
//通过BufferedReader读取一行
//如果已经读到输入流尾部,返回null,退出循环
//如果得到非空值,就尝试计算结果并返回
if ((expression = in.readLine()) == null) break;
System.out.println(("服务端收到信息:" + expression));
result = Calculator.cal(expression);
out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println((e.getLocalizedMessage()));
} finally {
//一些必要的清理工作
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if (out != null) {
out.close();
out = null;
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
}
}
}
Calculator,计算字符串的算术结果。注意0的ASCII码是48。
public class Calculator {
public static int cal(String expression) throws Exception {
char op = expression.charAt(1);
switch (op) {
case '+':
return (expression.charAt(0) - 48) + (expression.charAt(2) - 48);
case '-':
return (expression.charAt(0) - 48) - (expression.charAt(2) - 48);
case '*':
return (expression.charAt(0) - 48) * (expression.charAt(2) - 48);
case '/':
return (expression.charAt(0) - 48) / (expression.charAt(2) - 48);
}
throw new Exception("Calculator error");
}
}
客户端
Client,和服务器建立TCP连接,并发送和接收数据。
public class Client {
//默认的端口号
private static int DEFAULT_SERVER_PORT = 7777;
private static String DEFAULT_SERVER_IP = "127.0.0.1";
public static void send(String expression) {
send(DEFAULT_SERVER_PORT, expression);
}
public static void send(int port, String expression) {
System.out.println(("算术表达式为:" + expression));
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
try {
socket = new Socket(DEFAULT_SERVER_IP, port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
out.println(expression);
System.out.println(("结果为:" + in.readLine()));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if (out != null) {
out.close();
out = null;
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
}
}
}
测试代码
public class Test {
public static void main(String[] args) throws InterruptedException {
//运行服务器
new Thread(new Runnable() {
@Override
public void run() {
try {
BIOServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
//防止客户端先于服务器启动前执行代码
Thread.sleep(100);
final char[] op = {'+', '-', '*', '/'};
final Random random = new Random(System.currentTimeMillis());
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
//随机产生算术表达式
String expression = random.nextInt(10) + "" + op[random.nextInt(4)] +
(random.nextInt(10) + 1);
Client.send(expression);
try {
Thread.sleep(random.nextInt(1000));
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
}
}
