java网络编程2 -- BIO

BIO

什么叫BIO , BIO 是 block input output 的缩写 , 意思就是阻塞式的IO。这个是为了区别后面的NIO , 有关NIO ,后面再作介绍。服务器

举个简单的例子:我在使用bio的socket网络通讯中,会有下面的代码:网络

ServerSocket serverSocket = new ServerSocket(port);


        while (true) {
            Socket accept = serverSocket.accept();
            InputStream inputStream = accept.getInputStream();
            OutputStream outputStream = accept.getOutputStream();

            byte[] readBytes = new byte[100];
            inputStream.read(readBytes);
            System.out.println("===== " + new String(readBytes));
            outputStream.write((System.currentTimeMillis() + "").getBytes());
            accept.close();
        }

在 inputStream.read(readBytes);这一行,若是socket连接没有断,他会一直等待,直到读完socket的一次写入的全部的数据,或者是byte指定大小的数据。在连接没有断开的状况下,直到数据读完,才会执行下面的代码。(这个是bio的关键部分)。多线程

因此,若是在服务端,若是是单线程的,上面的代码,若是一个客户端连接进来,没有关闭,则第二个用户连接,发送数据不会有相应的。socket

——————————ide

因此针对,bio 的socket,出现了下面三种模型:性能

socket bio -- 单线程模式:

这个比较简单,直接写demo :测试

public class BioSimpleServer {

    private static int port = 8888;

    private static void init() throws IOException {

        ServerSocket serverSocket = new ServerSocket(port);


        while (true) {
            Socket accept = serverSocket.accept();
            InputStream inputStream = accept.getInputStream();
            OutputStream outputStream = accept.getOutputStream();

            byte[] readBytes = new byte[100];
            inputStream.read(readBytes);
            String readString = new String(readBytes);
            System.out.println("===== " + readString);
            outputStream.write((System.currentTimeMillis() + "").getBytes());
            if (readString != null && readString.trim().equalsIgnoreCase("quit")){
                accept.close();
            }
        }


    }

    public static void main(String[] args) throws IOException {
        init();
    }
}

这段代码,只是一个简单的demo , 没有考虑发送数据的长度,直接经过100个byte接收了。若是客户端,有数据过来,直接返回一个当前时间的毫秒数,若是请求的字符串是quit,则关闭链接。若是你采用telnet测试 , 只有第一个链接发送quit之后,第二个链接才会有相应。ui

socket bio -- 多线程模式:

上面能够看到,单线程模式的弊端是,一次只能服务一个客户端,若是有多个客户端过来连接,那就只能傻等,只有这个用户关闭连接之后,第二个客户端才能够连接的上,为了解决这个问题,出现了bio socket的多线程模式。线程

public class BioSimpleThread {
    private static int port = 8888;

    private static void init() throws IOException {

        ServerSocket serverSocket = new ServerSocket(port , 10);


        while (true) {
            final Socket accept = serverSocket.accept();

            new Thread() {
                @Override
                public void run() {

                    while (true){
                        try {
                            InputStream inputStream = accept.getInputStream();
                            OutputStream outputStream = accept.getOutputStream();
                            byte[] readBytes = new byte[100];
                            inputStream.read(readBytes);
                            String readString = new String(readBytes);
                            System.out.println("===== " + readString);
                            outputStream.write((System.currentTimeMillis() + "").getBytes());
                            if (readString != null && readString.trim().equalsIgnoreCase("quit")){
                                accept.close();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }


    }

    public static void main(String[] args) throws IOException {


        init();
    }
}

代码比较简单,一看就懂,这里添加了一个线程,只要有socket accept过来,就起一个线程,处理客户端的请求,这样能够保证,能够同时处理多个用户请求的状况。code

socket bio -- 线程池模式:

在看了多线程的bio 之后,咱们发现,只要有请求过来,就启动一个线程,若是有10万的客户端轻轻,就会启动10万个线程 ,这样就会出现cpu因为多个线程切换,线程相互竞争,服务端会愈来愈慢,直到服务器被托跨的问题,

为了不这种问题,咱们就须要规划本身的用户规模,考虑服务器的性能,单台机器上面,最多能够支持多少的在线用户。采用线程池的模式。

public class BioThreadPool {

    private static int port = 8888;

    static ExecutorService cachedThreadPool = Executors.newFixedThreadPool(100);


    private static void init() throws IOException {

        ServerSocket serverSocket = new ServerSocket(port);


        while (true) {
            final Socket accept = serverSocket.accept();

            cachedThreadPool.execute(new Thread() {
                @Override
                public void run() {
                    try {
                        InputStream inputStream = accept.getInputStream();
                        OutputStream outputStream = accept.getOutputStream();

                        byte[] readBytes = new byte[100];
                        inputStream.read(readBytes);
                        String readString = new String(readBytes);
                        System.out.println("===== " + readString);
                        outputStream.write((System.currentTimeMillis() + "").getBytes());
                        if (readString != null && readString.trim().equalsIgnoreCase("quit")){
                            accept.close();
                        }
                    } catch (Exception e) {
                        if (accept != null){
                            try {
                                accept.close();
                            } catch (IOException e1) {
                                e1.printStackTrace();
                            }
                        }
                        e.printStackTrace();
                    }
                }
            });

        }


    }

    public static void main(String[] args) throws IOException {
        init();
    }


}

这里采用了 static ExecutorService cachedThreadPool = Executors.newFixedThreadPool(100); , 避免单台服务器上面,启动过多的线程 , 将服务器托跨。

相关文章
相关标签/搜索