One BIO Demo
本文將實現一個輸入字元表示式,輸出算術結果的BIO程式。通過該程式能進一步幫助理解什麼是同步阻塞IO。
服務端
BIOServer,啟動服務端,並迴圈監聽客戶端連線,每監聽到一個請求,建立一個新執行緒處理資料。注意serverSocket.accept()方法,在未接收到連線時,會一直阻塞。
public class BIOServer { //預設的埠號 private static int DEFAULT_PORT = 7777; //單例的ServerSocket private static ServerSocket serverSocket; //根據傳入引數設定監聽埠,如果沒有引數呼叫以下方法並使用預設值 public static void start() throws IOException { //使用預設值 start(DEFAULT_PORT); } public synchronized static void start(int port) throws IOException { if (serverSocket != null) return; try { //通過建構函式建立ServerSocket //如果埠合法且空閒,服務端就監聽成功 serverSocket = new ServerSocket(port); System.out.println("服務端已啟動,埠號:" + port); //通過無線迴圈監聽客戶端連線 //如果沒有客戶端接入,將阻塞在accept操作上。 while (true) { Socket socket = serverSocket.accept(); new Thread(new ServerHandler(socket)).start(); } } finally { //一些必要的清理工作 if (serverSocket != null) { System.out.println("服務端已關閉。"); serverSocket.close(); serverSocket = null; } } } }
ServerHandler,執行緒處理資料流程。從輸入流讀資料,寫資料到輸出流。
public class ServerHandler implements Runnable { private Socket socket; public ServerHandler(Socket socket) { this.socket = socket; } @Override public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); String expression; int result; while (true) { //通過BufferedReader讀取一行 //如果已經讀到輸入流尾部,返回null,退出迴圈 //如果得到非空值,就嘗試計算結果並返回 if ((expression = in.readLine()) == null) break; System.out.println(("服務端收到資訊:" + expression)); result = Calculator.cal(expression); out.println(result); } } catch (Exception e) { e.printStackTrace(); System.out.println((e.getLocalizedMessage())); } finally { //一些必要的清理工作 if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } in = null; } if (out != null) { out.close(); out = null; } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } socket = null; } } } }
Calculator,計算字串的算術結果。注意0的ASCII碼是48。
public class Calculator { public static int cal(String expression) throws Exception { char op = expression.charAt(1); switch (op) { case '+': return (expression.charAt(0) - 48) + (expression.charAt(2) - 48); case '-': return (expression.charAt(0) - 48) - (expression.charAt(2) - 48); case '*': return (expression.charAt(0) - 48) * (expression.charAt(2) - 48); case '/': return (expression.charAt(0) - 48) / (expression.charAt(2) - 48); } throw new Exception("Calculator error"); } }
客戶端
Client,和伺服器建立TCP連線,併發送和接收資料。
public class Client { //預設的埠號 private static int DEFAULT_SERVER_PORT = 7777; private static String DEFAULT_SERVER_IP = "127.0.0.1"; public static void send(String expression) { send(DEFAULT_SERVER_PORT, expression); } public static void send(int port, String expression) { System.out.println(("算術表示式為:" + expression)); Socket socket = null; BufferedReader in = null; PrintWriter out = null; try { socket = new Socket(DEFAULT_SERVER_IP, port); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); out.println(expression); System.out.println(("結果為:" + in.readLine())); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } in = null; } if (out != null) { out.close(); out = null; } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } socket = null; } } } }
測試程式碼
public class Test { public static void main(String[] args) throws InterruptedException { //執行伺服器 new Thread(new Runnable() { @Override public void run() { try { BIOServer.start(); } catch (IOException e) { e.printStackTrace(); } } }).start(); //防止客戶端先於伺服器啟動前執行程式碼 Thread.sleep(100); final char[] op = {'+', '-', '*', '/'}; final Random random = new Random(System.currentTimeMillis()); new Thread(new Runnable() { @Override public void run() { while (true) { //隨機產生算術表示式 String expression = random.nextInt(10) + "" + op[random.nextInt(4)] + (random.nextInt(10) + 1); Client.send(expression); try { Thread.sleep(random.nextInt(1000)); }catch (InterruptedException e){ e.printStackTrace(); } } } }).start(); } }
