Java BIO模型

前面介绍了IO的分类和区别,本文将实现一个输入字符表达式,输出算术结果的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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值