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); , 避免單臺服務器上面,啓動過多的線程 , 將服務器託跨。

相關文章
相關標籤/搜索