BIO編程參考

網絡編程的基本模型是Client/Server模型,也就是兩個進程之間進行相互通信,其中服務端提供位置信息(綁定的IP地址和監聽端口),客戶端通過連接操作向服務端監聽的地址發起連接請求, 通過三 次握手建立連接, 如果連接建立成功, 雙方就可以通過網絡套接字 ( Socket) 進行通信。

在基於傳統同步阻塞模型開發中, ServerSocket負責綁定 IP 地址, 啓動監聽端口;Socket負責發起連接操作。連接成功之後, 雙方通過輸入和輸出流進行同步阻塞式通信。

Bl〇通信模型

採用BIO通信模型的服務端, 通常由一個獨立的Acceptor線程負責監聽客戶端的連接 ,當它接收到客戶端連接請求之後,會爲每個客戶端創建一個新的線程進行鏈路處理, 處理完成之後, 通過輸出流返回應答給客戶端, 最後銷燬線程,這就是典型的一請求一應答通信模型。

BIO最大的問題就是缺乏彈性伸縮能力,每當有一個新的客戶端請求接入時, 服務端必須創建一個新的線程處理新接入的客戶端鏈路, 一個線程只能處理一個客戶端連接。 當客戶端併發訪問量增加後, 服務端的線程個數和客戶端併發訪問數呈1:1的正比關係,由於線程是Java虛擬機珍貴的系統資源, 當線程數劇增之後, 系統的性能將急劇下降, 隨着併發訪問量的繼續增大, 系統會發生線程堆棧溢出、創建新線程失敗等問題 , 並最終導致進程宕機或僵死,不能對外提供服務 。而在高性能服務器應用領域,往往需要面向成幹上萬個客戶端的併發連接,這種模型顯然正法滿足高性能、高併發接入的場景 。

下面我們通過一個案例來說明同步阻塞IO的弊端

public class BioServer {

    public static void main(String[] args) throws IOException{
        int port = 8080;
        if(args != null && args.length >0 ){
            try{
                port = Integer.valueOf(args[0]);
            }catch (NumberFormatException e){

            }
        }

        ServerSocket server = null;
        try{
            server = new ServerSocket(port);
            System.out.println("the bio server is start in port :"+port);
            Socket socket = null;
            while (true){
                socket = server.accept();
                new Thread(new BioserverHandler(socket)).start();
            }
        }finally {
            if(server!=null){
                System.out.println("the time server close");
                server.close();
                server = null;
            }
        }
    }
}

BioServer根據傳入的參數設置監聽端口,如果沒有,使用默認值8080。然後new一個ServerSocket, 如果端口合法且沒有被佔用, 服務端監聽成功 。通過一個無限循環來監聽客戶端的連接, 如果沒有客戶端接入,則主線程阻塞在ServerSocket的accept操作上。當有新的客戶端接入的時候,以 Socket爲參數構造 BioServerHandler對象, BioServerHandler 是 一個 Runnable, 使用它爲構造函數的參數創建一個新的客戶端線程處理這條 socket鏈路,下面是BioServerHandler代碼:

public class BioServerHandler implements Runnable {

    private Socket socket;
    public BioServerHandler(Socket socket) {
        this.socket = socket;
    }
    public void run(){
        BufferedReader in = null;
        PrintWriter out = null;
        try{
            in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            out = new PrintWriter(this.socket.getOutputStream(),true);
            String body = null;
            while(true){
                body = in.readLine();
                if(body == null){
                    break;
                }
                System.out.print("The bio server receive :"+body);
                out.println(new Date());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(in!=null)
                    in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(out != null){
                out.close();
                out=null;
            }
           if(this.socket != null){
               try {
                   this.socket.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
               this.socket = null;
           }
        }
    }
}

BioClient類

客戶端創建Socket連接,向服務器發送消息,然後讀取服務器發送的消息, 隨後關閉連接,釋放資源,退出程序。

public class BioClient {
    public static void main(String[] args){
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try{
//            socket.connect(new InetSocketAddress("localhost", 8000));
            socket = new Socket("127.0.0.1",8080);
            out = new PrintWriter(socket.getOutputStream(),true);
            out.println("hello server !!");
            out.flush();
            System.out.println(" send msg to server succeed");
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String resp = in.readLine();
            System.out.println("receiver from server : " +resp);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                socket = null;
            }
            if(out != null){
                out.close();
                out = null;
            }
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                in = null;
            }
        }
    }
}

代碼在這了,大家可以自己跑下效果,我想大家在學習socket編程的時候,估計這樣的demo都寫爛了,好了,不說什麼了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章