栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

网络编程之中篇——BIO模型详述

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

网络编程之中篇——BIO模型详述

1、BIO介绍 1.1、BIO的概念

BIO(Blocking IO)同步阻塞IO模型,在JDK 1.4之前,建立网络链接采用的只有BIO的模型

需要服务端首先启动建立一个ServerSocket实例,然后客户端启动Socket实例对服务端进行连接通信,服务端通过调用accept方法等待接收客户端的连接请求,一旦接收到连接请求,就可以进行读写操作

在BIO编程中,相应的方法会产生阻塞:accept()、read()、write()、connect(),直至相关的操作等待完成之后才能继续后续代码处理,比如read操作,整个IO操作的过程都会阻塞,直至读取到数据之后才能继续执行(阻塞IO)

1.2、BIO支持高并发解决措施

如果BIO来考虑高并发问题,同时处理多个客户端的连接,就必须要使用多线程,即每次accept阻塞等待来自客户端的连接请求,一旦收到连接请求就将获取的套接字socket通过创建一个新的线程来处理IO操作,然后又继续通过accept接收客户端的连接

2、BIO编程

实现echo命令,客户端输入任何信息,服务端接收到信息并返回给客户端

2.1、只有一个客户端连接

服务端代码:

public class SingleServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            //创建ServerSocket实例并绑定端口
            serverSocket = new ServerSocket(7777);
            System.out.println("服务端绑定端口7777并启动啦");

            //等待并接受客户端连接
            socket = serverSocket.accept();
            //getRemoteSocketAddress() 获取连接的对方的IP和端口
            System.out.println("有新的客户端连接:" + socket.getRemoteSocketAddress());

            //进行读写操作
            inputStream = socket.getInputStream(); //读取客户端数据
            outputStream = socket.getOutputStream();//给客户端发送数据

            byte[] bytes = new byte[100];
            //可多次接受数据
            int len = 0;
            //判断当前的一个消息是否结束
            String recv = null;
            while ((len = inputStream.read(bytes)) != -1) {
                recv = new String(bytes, 0, len);
                System.out.println("客户端发送消息:" + recv);
                //封装返回给客户端
                outputStream.write(("[echo]" + recv + "n").getBytes());
                outputStream.flush();

                //判断当前业务结束标识:客户端发送exit
                if (recv != null && "exit".equals(recv.trim())) {
                    System.out.println("客户端断开即将断开连接");
                    break;
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭资源
                if (serverSocket != null) serverSocket.close();
                if (socket != null) socket.close();
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

客户端代码:

public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;

        //获取从键盘输入的内容
        Scanner scanner = new Scanner(System.in);
        scanner.useDelimiter("n");
        try {
            //创建socket实例
            socket = new Socket();

            //连接服务端
            socket.connect(new InetSocketAddress("127.0.0.1",7777));
            System.out.println("客户端连接服务端成功");

            //读写操作
            outputStream = socket.getOutputStream();
            inputStream = socket.getInputStream();
            byte[] bytes = new byte[100];

            while (scanner.hasNext()) {
                //获取键盘内容
                String msg = scanner.next();
                if (msg == null || "".equals(msg.trim())) continue;
                //发给服务端
                outputStream.write(msg.getBytes());
                outputStream.flush();

                //接收服务端返回的数据
                int num = inputStream.read(bytes);
                System.out.println("服务端返回:"+new String(bytes,0,num));

                if ("exit".equals(msg.trim())) {
                    //特定结束
                    System.out.println("客户端主动断开连接啦");
                    break;
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            try {
                if (socket != null) socket.close();
                if (outputStream != null) outputStream.close();
                if (inputStream != null) inputStream.close();

            } catch (Exception e) {}
        }
    }
}

2.2、BIO支持高并发

public class MultiThreadServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            //创建ServerSocket实例
             serverSocket = new ServerSocket(9999);
            System.out.println("服务端绑定端口9999并启动啦");

            //等待多客户端的连接,不断循环等待客户端的连接
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("有新用户连接啦:"+socket.getRemoteSocketAddress());
                //每一个新用户连接都交给一个新线程来处理,重点:将Socket交给子线程
                new Thread(new RunableHandler(socket)).start();
            }

        } catch (IOException e) {

        }
    }
}
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class RunableHandler implements Runnable {
    private Socket socket;//socket实例,每一个线程单独处理一个socket
    public RunableHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

        try {
            //进行读写操作
            InputStream inputStream = socket.getInputStream(); //读取客户端数据
            OutputStream outputStream = socket.getOutputStream();//给客户端发送数据

            byte[] bytes = new byte[100];
            //可多次接受数据
            int len = 0;
            //判断当前的一个消息是否结束
            String recv = null;
            while ((len = inputStream.read(bytes)) != -1) {
                recv = new String(bytes, 0, len);
                System.out.println("客户端:"+socket.getRemoteSocketAddress()+" 发送消息:" + recv);
                //封装返回给客户端
                outputStream.write(("[echo]" + recv + "n").getBytes());
                outputStream.flush();

                //判断当前业务结束标识:客户端发送exit
                if (recv != null && "exit".equals(recv.trim())) {
                    System.out.println("客户端:"+socket.getRemoteSocketAddress()+" 断开即将断开连接");
                    break;
                }
            }

            //关闭资源
            socket.close();
            inputStream.close();
            outputStream.close();

        } catch (Exception e) {}

    }
}

通过对BIO的高并发的实现可知:在BIO实现的过程中,为了支持多客户端请求,每一个客户端的连接请求都会新分配一个线程来做处理。并不意味着线程创建的越多越好,每创建一个线程,需要消耗的内存资源,而内存资源是有限的,另线程越多,在系统进行调度的过程中上下文的切换也会消耗性能, 通过BIO来实现高并发,创建的线程越多反而会是性能大打折扣。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/310458.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号