zoukankan      html  css  js  c++  java
  • Java高并发网络编程(二)BIO

     一、阻塞

    服务器端

    public class BIOServer {
    
        public static void main(String[] args) throws Exception {
            ServerSocket sc = new ServerSocket(9093);
            System.out.println("服务器启动成功!");
            while (!sc.isClosed()) {
                Socket request = sc.accept(); // 阻塞
                System.out.println("收到新连接:" + request.toString());
                try {
                    InputStream is = request.getInputStream(); // net+i/o
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"));
                    String msg;
                    while ((msg = reader.readLine()) != null) { // 没有数据会阻塞
                        if (msg.length() == 0) {
                            break;
                        }
                        System.out.println(msg);
                    }
                    System.out.println("收到数据,来自:" + request.toString());
                } catch (Exception e) {
                    // TODO: handle exception
                } finally {
                    try {
                        request.close();
                    } catch (Exception e2) {
                        // TODO: handle exception
                    }
                }
    
            }
        }
    }

    sc.accept()会使服务端一直阻塞,直到连接被创建

    InputStream也是阻塞的

    客户端

    public class BIOClient {
    
        public static void main(String[] args) throws IOException {
            Socket s = new Socket("localhost", 9093);
            OutputStream out = s.getOutputStream();
    
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入");
            String msg = scanner.nextLine();
            out.write(msg.getBytes());
            scanner.close();
            s.close();
        }
    
    }

    OutputStream也是阻塞的,写完成之后才会返回

    当同时启动两个客户端的时候

     服务器只建立了一个连接,并等待客户端的输入

    我们在被等待的客户端输入123

     服务器收到123,并建立了一个新的连接

    这不满足我们的需求,下面引入多线程,升级服务器端

    二、多线程引入

    线程池

    public class BIOServer {
    
        private static ExecutorService threadPool = Executors.newCachedThreadPool();
    
        public static void main(String[] args) throws Exception {
            ServerSocket sc = new ServerSocket(9093);
            System.out.println("服务器启动成功!");
            while (!sc.isClosed()) {
                Socket request = sc.accept(); // 阻塞
                System.out.println("收到新连接:" + request.toString());
                threadPool.execute(() -> {
                    try {
                        InputStream is = request.getInputStream(); // net+i/o
                        BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"));
                        String msg;
                        while ((msg = reader.readLine()) != null) {
                            if (msg.length() == 0) {
                                break;
                            }
                            System.out.println(msg);
                        }
                        System.out.println("收到数据,来自:" + request.toString());
                    } catch (Exception e) {
                        // TODO: handle exception
                    } finally {
                        try {
                            request.close();
                        } catch (Exception e2) {
                            // TODO: handle exception
                        }
                    }
                });
            }
        }

    启动三个客户端,分别输入123、456、789

     不必再等待其他客户端

     三、服务端与浏览器交互

    上面简单的C/S程序不能满足现实场景,下面进行服务端与浏览器的交互。

    我们在浏览器,输入服务端的地址127.0.0.1:9093

     

     我们发现服务端收到上面的信息,但是浏览器中没有访问到任何内容

     

     原因:浏览器与服务端的交互使用的是HTTP协议

    必须满足一定的格式:

    1.请求数据包

     上图没有第三部分和第四部分

    2.响应数据包

     响应状态码

     因此,我们按照HTTP协议的格式,在服务端编写响应浏览器的内容,浏览器就可以收到我们的响应信息

    public class BIOServer {
    
        private static ExecutorService threadPool = Executors.newCachedThreadPool();
    
        public static void main(String[] args) throws IOException {
            ServerSocket serverSocket = new ServerSocket(9096);
            System.out.println("tomcat 服务器启动成功");
            while (!serverSocket.isClosed()) {
                Socket request = serverSocket.accept();
                System.out.println("收到新连接:" + request.toString());
                threadPool.execute(() -> {
                    try {
                        InputStream inputStream = request.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
                        String msg;
                        while ((msg = reader.readLine()) != null) {
                            if (msg.length() == 0) {
                                break;
                            }
                            System.out.println(msg);
                        }
                        System.out.println("收到数据,来自:" + request.toString());
                        // 响应结果
                        OutputStream outputStream = request.getOutputStream();
                        outputStream.write("HTTP/1.1 200 ok
    ".getBytes());
                        outputStream.write("Content-Length: 40
    
    ".getBytes());
                        outputStream.write("<button type=\"button\">Click Me!</button>".getBytes());
                    } catch (Exception e) {
                        // TODO: handle exception
                    } finally {
                        try {
                            request.close();
                        } catch (Exception e) {
                            // TODO: handle exception
                        }
                    }
                });
    
            }
            serverSocket.close();
        }
    }

    浏览器访问服务器

    概念总结:

    BIO:blocking IO,资源不可用时,IO请求一直阻塞,直到收到反馈结果(有数据或超时)。

    NIO:non-blocking IO,资源不可用时,IO请求离开返回,返回数据标识资源不可用。

    同步IO:synchronous IO,应用阻塞在发送或接收数据的状态,直到数据成功传输或返回失败。

    异步IO:asynchronous IO,应用发送或接收数据后立刻返回,实际处理时异步执行的。

     

     阻塞带来的问题:阻塞导致在处理网络I/O时,一个线程只能处理一个网络连接。

  • 相关阅读:
    Oracle基础知识整理
    linux下yum安装redis以及使用
    mybatis 学习四 源码分析 mybatis如何执行的一条sql
    mybatis 学习三 mapper xml 配置信息
    mybatis 学习二 conf xml 配置信息
    mybatis 学习一 总体概述
    oracle sql 语句 示例
    jdbc 新认识
    eclipse tomcat 无法加载导入的web项目,There are no resources that can be added or removed from the server. .
    一些常用算法(持续更新)
  • 原文地址:https://www.cnblogs.com/aidata/p/11521878.html
Copyright © 2011-2022 走看看