zoukankan      html  css  js  c++  java
  • BIO基本介绍以及使用

    BIO就是传统的java io编程,其相关的类和接口在java.io 上。

    BIO(Blocking I/O): 同步阻塞IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就会新起一个线程进行处理,如果这个线程不做任何事情会造成不必要的线程开销,可以通过线程池机制改善。

    BIO适用于连接数较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用,JDK1.4 以前的唯一选择。

    1. BIO 简单流程

    1. 服务端启动一个ServerSocket

    2.客户端启动Socket对服务器进行通信,默认情况下服务器端需要对每个客户建立一个线程与之通讯

    3.客户端发出请求后,先咨询服务器是否有线程响应,如果没有则会等待,或者被拒绝

    4.如果有响应,客户端线程会等待请求结束后,在继续执行

    2.应用实例

    1》使用BIO模型监听一个服务器端,监听6666端口,当有客户端连接时,就启动一个线程与之通讯

    2》要求使用线程池机制改善,可以连接多个客户端

    3》服务器端可以接收客户端发送的数据(telnet 方式即可)

    3. 编程测试

    package cn.qlq;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class BIOServer {
    
        
        public static void main(String[] args) throws IOException {
            // 1. 创建线程池
            ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
            // 2. 创建ServerSocket
            ServerSocket serverSocket = new ServerSocket(6666);
            System.out.println("服务器启动了====");
            while (true) {
                final Socket socket = serverSocket.accept();
                System.out.println("接收到一个客户端连接");
                newCachedThreadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        handle(socket);
                    }
                });
                
            }
        }
        
        public static void handle(Socket socket) {
            System.out.println("threadId: " + Thread.currentThread().getId() );
            try {
                byte[] bytes = new byte[1024];
                // 通过sockets读取输入流
                InputStream inputStream = socket.getInputStream();
                // 循环读取数据
                while (true) {
                    System.out.println("threadId: " + Thread.currentThread().getId() + " 等待read");
                    int read = inputStream.read(bytes);
                    if (read != -1) {
                        String readStr = new String(bytes, 0, read);
                        System.out.println("threadId: " + Thread.currentThread().getId() + "	" + readStr);
                    } else {
                        break;
                    }
                }
                
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                System.out.println("关闭和客户端的连接");
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    启动服务端使用Telnet测试:

    1. telnet连接

    telnet 127.0.0.1 6666

    查看服务器日志

    服务器启动了====
    接收到一个客户端连接
    threadId: 12
    threadId: 12 等待read

    2. CTRL + ] 键进入命令行,然后发送字符串命令

    Escape 字符为 'CTRL+]'
    
    
    Microsoft Telnet> send 456789
    发送字符串 456789
    Microsoft Telnet> send hello china!
    发送字符串 hello china!
    Microsoft Telnet>

    3. 查看服务器控制台

    服务器启动了====
    接收到一个客户端连接
    threadId: 12
    threadId: 12 等待read
    threadId: 12    456789
    threadId: 12 等待read
    threadId: 12    hello china!
    threadId: 12 等待read

    4. 新启动一个telnet窗口查看

    欢迎使用 Microsoft Telnet Client
    
    Escape 字符为 'CTRL+]'
    
    
    Microsoft Telnet> send 868655
    发送字符串 868655
    Microsoft Telnet>

    5. 查看服务器控制台日志

    服务器启动了====
    接收到一个客户端连接
    threadId: 12
    threadId: 12 等待read
    threadId: 12    456789
    threadId: 12 等待read
    threadId: 12    hello china!
    threadId: 12 等待read
    接收到一个客户端连接
    threadId: 13
    threadId: 13 等待read
    threadId: 13    868655
    threadId: 13 等待read

    6. 断开一个

    Microsoft Telnet> quit

    控制台日志

    关闭和客户端的连接

    4. BIO问题

    1》 每个请求都需要创建独立的线程,与对应的客户端进行Read,业务处理,数据Write

    2》当并发树较大时,需要创建大量线程来处理连接,系统资源占用较大

    3》连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在Read操作上,造成线程资源浪费

      解决类似的问题就需要用NIO技术。

    【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】
  • 相关阅读:
    devise 异步发邮件
    ubuntutweak for lucid
    960gs blueprint
    Amoeba for mysql 0.31发布(读写分离、负载均衡、Failover、数据切分)
    Google App Servlet容器转型 – 从Tomcat到Jetty
    DBeaver
    用simple from暂不用formtastic
    [SQL Server]ORDER BY的问题
    PHP pathinfo() 函数
    php中使用head进行二进制流输出,让用户下载PDF等附件的方法
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/14426603.html
Copyright © 2011-2022 走看看