經過TCP交互以及Socket API來看阻塞式IO

1、TCP交互以及Socket API調用

三次握手創建TCP之後開始傳輸數據。html

Accept後對於服務端來講整個socket建立完畢,直接進入read狀態。read是一個阻塞調用,所謂阻塞是指服務器進入等待,直到read返回。java

read實際上是的主要時間是等待數據ready:api

  1. 客戶端發送後,有可能發送端的發送窗口已經滿了,須要等待,記爲T1。
  2. 進入發送窗口後,TCP傳輸自己須要時間,T2。
  3. 接收端數據後從內核拷貝到用戶空間也須要時間,T3

因此read阻塞的時間至少須要T1+T2+T3,其中T1+T2的時間爲等待數據的時間服務器

2、進程讀取數據的過程

3、java演示

接下來用java源碼來演示BIO的過程,爲了看到效果特地在客戶端加入了兩次sleep來標識客戶端IO的時間,而服務端的read卻要一直等待阻塞在這個客戶端的IO上。socket

源碼參考async

服務端代碼

import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SocketBioServer {
    static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress("localhost", 8080));
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println(time() + "->accepted, begin to read......");
                String result = readBytes(socket.getInputStream());
                System.out.println(time() + "->" + result);
                socket.close();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    static String readBytes(InputStream is) throws Exception {
        long start = 0;
        int total = 0;
        long begin = System.currentTimeMillis();
        int count = 0;
        while ((count = is.read()) > -1) {//block,有數據寫入的時候纔會返回值。客戶端關閉後纔會返回-1
            if (start == 0) {
                start = System.currentTimeMillis();
            }
            total += count;
        }
        //讀完數據的時間
        long end = System.currentTimeMillis();
        return "wait=" + (start - begin) + "ms,read=" + (end - start) + "ms,total=" + total + "bs";
    }

    static String time() {
        return sdf.format(new Date());
    }
}

客戶端源碼

import java.net.InetSocketAddress;
import java.net.Socket;

public class SocketBioClient {
    public static void main(String[] args) {
        try {
            Socket s = new Socket();
            s.connect(new InetSocketAddress("localhost", 8080));
            Thread.sleep(5000);//模擬數據發送前的等待
            s.getOutputStream().write(prepareBytes());
            Thread.sleep(1000);//模擬寫入數據須要的時間
            s.close();//關閉後客戶端才能返回-1
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    static byte[] prepareBytes() {
        byte[] bytes = new byte[1024 * 1024 * 1];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = 1;
        }
        return bytes;
    }
}

執行結果

23:03:14->accepted, begin to read......
23:03:20->wait=5005ms,read=1002ms,total=1048576bs

經過上述能夠看到read一直阻塞等待客戶端的IO寫入。tcp

相關文章
相關標籤/搜索