zoukankan      html  css  js  c++  java
  • 通过TCP交互以及Socket API来看阻塞式IO

    一、TCP交互以及Socket API调用

    三次握手建立TCP以后开始传输数据。

    Accept后对于服务端来说整个socket创建完毕,直接进入read状态。read是一个阻塞调用,所谓阻塞是指服务器进入等待,直到read返回。

    read其实是的主要时间是等待数据ready:

    1. 客户端发送后,有可能发送端的发送窗口已经满了,需要等待,记为T1。
    2. 进入发送窗口后,TCP传输本身需要时间,T2。
    3. 接收端数据后从内核拷贝到用户空间也需要时间,T3

    所以read阻塞的时间至少需要T1+T2+T3,其中T1+T2的时间为等待数据的时间

    二、进程读取数据的过程

    三、java演示

    接下来用java源码来演示BIO的过程,为了看到效果特意在客户端加入了两次sleep来标识客户端IO的时间,而服务端的read却要一直等待阻塞在这个客户端的IO上。

    源码参考

    服务端代码

    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写入。

  • 相关阅读:
    mybatis自动生成代码配置文件
    Struts2的类型转换器
    CSS布局自适应高度终极方法
    Winform WebBrowser控件对访问页面执行、改写、添加Javascript代码
    利用using语句解决Lock抛出异常时发生死锁的问题
    Flash与Silverlight终极大比拼
    System.Collections.Specialized.NameValueCollection PostVars
    Hook浏览器控件WebBrowser对WININET.dll的调用
    WebBrowser中打开新页面保留sessionid
    Linksys路由器自动重启加流量
  • 原文地址:https://www.cnblogs.com/Brake/p/14033626.html
Copyright © 2011-2022 走看看