網絡編程中,服務端提供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