網絡編程 - BIO

網絡編程中,服務端提供IP和監聽端口,客戶端經過服務端的IP和端口發送請求,進行通訊。這篇是講傳統的同步阻塞模型--BIO。java

客戶端

BioClient主要是建立一個Socket,並經過Socket把請求發送服務端,代碼以下:編程

public class BioClient {
    public static void main(String[] args) {
        try {
            // 經過服務IP,端口建立一個Socket
            Socket socket = new Socket(Const.IP, Const.PORT);
            // 獲取Socket輸出流
            OutputStream outputStream = socket.getOutputStream();
            // 輸出流
            outputStream.write("hello world".getBytes());
            // 關閉流
            outputStream.close();
            // 關閉Socket
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服務端

服務端先建立一個ServerSocket,用於監聽指定端口的鏈接請求。accept方法會一直阻塞,直到新的鏈接創建,創建後,建立一個Socket與客戶端進行通訊。在讀取輸入流的時候,br.readLine()也是阻塞的。服務器

public class BioServer {
    public static void main(String[] args) {
        try {
            //獲取ServerSocket,綁定服務器的端口
            ServerSocket serverSocket = new ServerSocket(Const.PORT);
            while (true) {
                // 建立一個Socket接收鏈接
                Socket socket = serverSocket.accept();
                // 獲取輸入流
                InputStream inputStream = socket.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
                String message;
                while (null != (message = br.readLine())) {
                    System.out.println(message);
                }
                // 關閉流
                inputStream.close();
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的實例中,有個比較大的缺點,就是同時只能處理一個鏈接,要想處理多個併發客戶端,咱們能夠簡單地用多線程來管理,每次有新的sockert,建立一個線程或則放入線程池來處理。
咱們把sockert的部分抽出來:網絡

public class BioServerHandler implements Runnable {
    private Socket socket;

    public BioServerHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            // 獲取輸入流
            InputStream inputStream = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            String message;
            while (null != (message = br.readLine())) {
                System.out.println(message);
            }
            // 關閉流
            inputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

建立線程的方式:多線程

public class BioServer2 {
    public static void main(String[] args) {
        try {
            //獲取ServerSocket,綁定服務器的端口
            ServerSocket serverSocket = new ServerSocket(Const.PORT);
            while (true) {
                // 建立一個Socket接收鏈接
                Socket socket = serverSocket.accept();
                new Thread(new BioServerHandler(socket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

建立線程池的方式:併發

public class BioServer3 {
    private static ExecutorService executorService
            = Executors.newFixedThreadPool(5);

    public static void main(String[] args) {
        try {
            //獲取ServerSocket,綁定服務器的端口
            ServerSocket serverSocket = new ServerSocket(Const.PORT);
            while (true) {
                // 建立一個Socket接收鏈接
                Socket socket = serverSocket.accept();
                executorService.execute(new BioServerHandler(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BioServer2和BioServer3經過線程,能夠比BioServer同時處理更多的客戶端請求,可是依然存在着不足:在任什麼時候候,都有大量的線程處於休眠狀態,只能等待輸入或則輸出數據就緒,浪費資源。爲此,java提供了另一直方式-NIO。socket

相關文章
相關標籤/搜索