BIO 详解

欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot

调用者主动等待调用的结果

简介

早期的jdk中,采用BIO通信模式:
    通常有一个acceptor(消费者) 去负责监听客户端的连接。
    它接收到客户端的连接请求之后为每个客户端创建一个线程进行链路处理,处理完成之后,线程销毁。
    一个客户端连接,对应一个处理线程。他们之间的对应关系是 1:1。

由于客户端连接和服务端的处理之间的对应关系是1:1,如果遇到任务比较大,处理比较慢。
或者并发量比较大的情况下,系统会创建大量的线程。从而导致服务器线程暴增,性能急剧下降,甚至宕机。

客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try {
            //创建连接
            socket = new Socket("127.0.0.1", 8080);
            
            //输出流:发送数据
            out = new PrintWriter(socket.getOutputStream(), true);
            out.println("发送数据");
            
            //输入流:接收数据
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //阻塞:未收到数据就等在这里
            String resp = in.readLine();
            System.out.println("回应:" + resp);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            out.close();
            out = null;
        }
    }
}

服务端

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

public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            //创建服务端
            serverSocket = new ServerSocket(8080);
            Socket socket = null;
            while (true) {
                //从socket的队列中获取socket的连接
                //相当于一个消费者
                ///当前的线程阻塞在accept方法上面。该方法一直阻塞,除非获取到socket连接返回
                socket = serverSocket.accept();

                // 获得到socket连接之后,分配线程任务进行处理
                new Thread(new Handler(socket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                serverSocket = null;
            }
        }
    }
}

处理线程

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Handler implements Runnable {

    private Socket socket;

    public Handler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader in = null;
        PrintWriter out = null;

        try {
            //输入流:接收数据
            in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));

            //接收数据
            String receive = null;

            //输出流:发送数据
            out = new PrintWriter(this.socket.getOutputStream(), true);

            //回应结果
            String currentTime = null;

            while (true) {
                //输入流:读取数据的部分是阻塞的
                //由于使用的是阻塞IO,那么read方法一直处于阻塞状态,要等到数据传送完成才结束(返回-1)
                //1,内核程序从网卡中把数据读取到内核空间中,是一直阻塞的。
                //2,用户程序把内核空间的数据复制到用户空间的过程,是阻塞的。
                //这两个过程中,对应的程序部分就是read方法的阻塞
                receive = in.readLine();
                if (receive == null) {
                    break;
                }
                System.out.println(receive);

                //输出流:输出数据
                currentTime = "收到";
                out.println(currentTime);
            }
        } catch (IOException e) {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }

            if (out != null) {
                out.close();
                out = null;
            }
        }
    }
}
posted @ 2019-09-07 10:17  LittleDonkey  阅读(809)  评论(0编辑  收藏  举报