BIO编程学习
  Op9yysgqYUmV 2023年11月02日 87 0


BIO网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请求, 通过三 次握手建立连接, 如果连接建立成功, 双方就可以通过网络套接字 ( Socket) 进行通信。

在基于传统同步阻塞模型开发中, ServerSocket负责绑定 IP 地址, 启动监听端口;Socket负责发起连接操作。连接成功之后, 双方通过输入和输出流进行同步阻塞式通信。

Bl〇通信模型

采用BIO通信模型的服务端, 通常由一个独立的Acceptor线程负责监听客户端的连接 ,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理, 处理完成之后, 通过输出流返回应答给客户端, 线程销毁。这就是典型的一请求一应答通信模型。

该模型最大的问题就是缺乏弹性伸缩能力, 当客户端并发访问量增加后, 服务端的线程个数和客户端并发访问数呈1:1的正比关系,由于线程是Java虚拟机珍贵的系统资源, 当线程数剧增之后, 系统的性能将急剧下降, 随着并发访问量的继续增大, 系统会发生线程堆栈溢出、创建新线程失败等问题 , 并最终导致进程宕机或僵死,不能对外提供服务 。

下面我们通过一个案例来说明同步阻塞IO的弊端

public class BioServer {

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

            }
        }

        ServerSocket server = null;
        try {
            server = new ServerSocket(port);
            System.out.println("the bio server is start in port :" + port);
            Socket socket = null;
            while (true) {
                socket = server.accept();
                new Thread(new BioServerHandler(socket)).start();
            }
        } finally {
            if (server != null) {
                System.out.println("the bio server close");
                server.close();
                server = null;
            }
        }
    }
}

BioServer根据传入的参数设置监听端口,如果没有,使用默认值8080。然后new一个ServerSocket, 如果端口合法且没有被占用, 服务端监听成功 。通过一个无限循环来监听客户端的连接, 如果没有客户端接入,则主线程阻塞在ServerSocket的accept操作上。当有新的客户端接入的时候,以 Socket为参数构造 BioServerHandler对象, BioServerHandler 是 一个 Runnable, 使用它为构造函数的参数创建一个新的客户端线程处理这条 socket链路,下面是BioServerHandler代码:

public class BioServerHandler implements Runnable {

    private Socket socket;
    public BioServerHandler(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 body = null;
            while(true){
                //通过BufferedReader读取一行,如果已经读到了输入流的尾部,则返回値为null
                body = in.readLine();
                if(body == null){
                    break;
                }
                System.out.print("The bio server receive :"+body);
                //通过PrintWriter的println函数发送数据给客户端
                out.println(new Date());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(in!=null)
                    in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(out != null){
                out.close();
                out=null;
            }
           if(this.socket != null){
               try {
                   this.socket.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
               this.socket = null;
           }
        }
    }
}

BioClient类

客户端创建Socket连接,向服务器发送消息,然后读取服务器发送的消息, 随后关闭连接,释放资源,退出程序。

public class BioClient {
    public static void main(String[] args){
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try{
//            socket.connect(new InetSocketAddress("localhost", 8000));
            socket = new Socket("127.0.0.1",8080);
            out = new PrintWriter(socket.getOutputStream(),true);
            out.println("hello server !!");
            out.flush();
            System.out.println(" send msg to server succeed");
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String resp = in.readLine();
            System.out.println("receiver from server : " +resp);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                socket = null;
            }
            if(out != null){
                out.close();
                out = null;
            }
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                in = null;
            }
        }
    }
}

BIO主要的问题在于每当有一个新的客户端请求接入时, 服务端必须创建一个新的线程处理新接入的客户端链路, 一个线程只能处理一个客户端连接。在高性能服务器应用领域,往往需要面向成干上万个客户端的并发连接,这种模型显然正法满足高性能、高并发接入的场景 。

 

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
Op9yysgqYUmV