1. 程式人生 > >NIO入門之BIO

NIO入門之BIO

傳統BIO程式設計

網路程式設計的基本模型是Client-Server模型,也就是兩個程序之間相互通訊,其中服務端提供位置資訊(繫結的IP地址和監聽埠),客戶端通過連線操作向服務端監聽的埠發起連線請求,通過三次握手建立連線,如果連線成功,雙方就可以通過網路套接字(Socket)進行通訊。

在傳統的BIO程式設計中,ServerSocket負責繫結IP地址,啟動埠監聽,Socket負責發起連線請求,連線成功之後,雙方通過輸入和輸出流進行同步阻塞通訊。

下面通過TimeServer的一個例子,回顧和熟悉BIO程式設計

BIO通訊模型圖


可以看到再改模型中,有一個Acceptor執行緒負責監聽客戶端的連線,併為每個請求建立一個新的執行緒進行處理。

我們可以發現該模型最大問題就是缺乏彈性伸縮能力,服務端和客戶端執行緒個數是1比1的關係。

BIO的TimeServer

package nio.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by jj on 2018/12/23.
 */
public class TimeServer {

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

            }
        }

        ServerSocket server = null;

        try{
            server = new ServerSocket(port);
            Socket socket = null;
            while (true){
                socket = server.accept();
                new Thread(new TimeServerHandler(socket)).start();
            }
        }finally {
            if (server!= null){
                server.close();
                server = null;
            }
        }
    }
}

如果沒有客戶端請求,則阻塞在server.accept操作上,如果有,則建立一個TimeServerHandler的Runnable執行緒,處理客戶端的Socket鏈路

下面,我們看一下TimeServerHandler

public class TimeServerHandler implements Runnable{

    private Socket socket;

    public TimeServerHandler(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 curentTime = null;
            String body = null;
            while (true){
                body = in.readLine();
                if (body == null)
                    break;
                System.out.println("the time server receive order:" + body);
                curentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new Date(
                        System.currentTimeMillis()
                ).toString():"BAD ORDER";
                out.println(curentTime);
            }
        } catch (Exception e) {
            if (in != null){
                try {
                    in.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (out != null){
                out.close();
                out = null;
            }
            if (this.socket !=null){
                try {
                    this.socket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                this.socket = null;
            }
        }
    }
}

可以看到run中的功能為讀取客戶端請求,並通過PrintWriter返回給客戶端相應。

下面我們看一下客戶端的程式碼

public class TimeClient {

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

            }
        }
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try{
            socket = new Socket("127.0.0.1",port);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(),true);
            out.println("QUERY TIME ORDER");
            
            String resp = in.readLine();
            System.out.print(resp);

        }finally {
            if (out != null){
                out.close();
                out = null;
            }
            if (in != null){
                in.close();
                in = null;
            }
            if (socket != null){
                socket.close();
                socket = null;
            }
        }
    }
}