高性能编程——BIO阻塞式网络编程

文章目录

  • BIO编程初体验
    • 服务端
    • 客户端
    • 结果展示
      • 客户端:
      • 服务端
    • 存在的问题
    • 用浏览器访问服务端
      • Http协议 - 请求数据包解析
        • 第一部分
        • 第二部分
        • 第三部分
        • 第四部分
        • http响应状态码
    • BIO -阻塞IO的含义
      • 阻塞(blocking)IO
      • 非阻塞(non-blocking)IO
      • 同步(syschronous)IO
      • 异步(asynchronous)IO
      • 总结

BIO编程初体验

服务端

先写一段服务端代码,用于接收客户端信息:

public class BIOServer {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务器启动成功");
        while(!serverSocket.isClosed()){
            Socket request = serverSocket.accept();//阻塞
            System.out.println("收到新连接:"+request.toString());
            try{
                //接收数据,打印
                InputStream inputStream = request.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
                String msg;
                while((msg = reader.readLine())!=null){//读操作是阻塞的
                    if(msg.length() == 0){
                        break;
                    }
                    System.out.println(msg);
                }
                System.out.println("收到数据,来自:"+request.toString());
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                request.close();
            }
        }
    }
}

上面主要需要注意的点就是serverSocket是阻塞接收客户端信息的,也就是说如果客户端的请求还没有过来的话,该线程就会被阻塞。

客户端

写完服务端再来写一下客户端,主要功能就是实现向服务端传输信息的功能:

public class BIOClient {
    private static Charset charset = Charset.forName("UTF-8");

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost",8080);
        OutputStream out = socket.getOutputStream();

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入:");
        String s = scanner.nextLine();
        out.write(s.getBytes(charset));//阻塞,写完成
        scanner.close();
        socket.close();
    }
}

上述代码其实很好理解,用套接字指定了ip和端口,完成了定向的数据传输。

结果展示

启动服务端和客户端来做一次测试:

客户端:

高性能编程——BIO阻塞式网络编程_第1张图片

服务端

高性能编程——BIO阻塞式网络编程_第2张图片

存在的问题

首先就是上述服务端代码中的读是阻塞的,如果在还没读取到数据的时候,是无法获取到新的连接的。这个时候就要用到线程池了,通过不同的线程去执行,就可以绕开堵塞的线程而获取新的连接了。

用浏览器访问服务端

上面是我们自己写的客户端去访问,结果是走的通的,那么我们此处使用浏览器来访问客户端是什么效果呢?做个实验:
高性能编程——BIO阻塞式网络编程_第3张图片
显然浏览器是回应无法打开页面,再看服务端:

GET / HTTP/1.1
Host: localhost:8080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Upgrade-Insecure-Requests: 1
Cookie: Idea-d0b330b7=0a0e8b39-9808-4855-b0fc-718952998b50
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Connection: keep-alive

这是一个http协议的数据包,来详细解一下

Http协议 - 请求数据包解析

可以把Http数据包主要分为四个部分

第一部分

第一行就是请求行,里面的GET就是请求类型,后面一般会跟资源路径以及HTTP版本。(我的数据包里没有资源路径,因为我没指定)。

第二部分

请求头部,就是紧接着请求行之后的部分,用来说明服务器要使用的附加信息。

第三部分

空行,请求头部后面的空行是必须的,请求头部和数据主体之间必须有换行

第四部分

请求数据也叫主体,可以添加任意的数据。这个例子的请求数据为空。

http响应状态码

高性能编程——BIO阻塞式网络编程_第4张图片

BIO -阻塞IO的含义

阻塞(blocking)IO

资源不可用时,IO请求一直阻塞,直到反馈结果(有数据或超时)。

非阻塞(non-blocking)IO

资源不可用时,IO请求离开返回,返回数据标识资源不可用。

同步(syschronous)IO

应用阻塞在发送或接收数据的状态,直到数据成功传输或返回失败。

异步(asynchronous)IO

应用发送或接收数据后立刻返回,实际处理是异步返回的。

总结

简述一下上面的差异。阻塞和非阻塞强调的是资源获取的方式。是拿不到资源苦苦等还是拿不到就放弃。而同步和异步强调的则是获取资源后的处理方式,是处理完了再返回结果还是先告诉他一声再自己处理。

上面使用的API中,ServerSocket#accpet、InputStream#read都是阻塞的API。操作系统底层的API中,默认Socket操作都是Blocking型,send/recv等接口都是阻塞的。

你可能感兴趣的:(高性能编程)