JAVA网络编程:BIO

首先安装netcat(window安装教程)来模拟客户端

BIO(Blocking IO)顾名思义阻塞式IO

在服务端的主要实现代码是

ServerSocket.accept();
InputStream.read(), OutputStream.write()

这些方法都是阻塞的方法,没有请求就会一直阻塞直到有新连接进来,或数据输入输出

单线程BIO
public class ServerBio {
    public static void main(String[] args) throws IOException {
    	//监听9000端口
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            //未有连接,阻塞
            Socket socket = serverSocket.accept();
            System.out.println("一个新的连接进来");

            handler(socket);
            socket.close();
        }
    }

    private static void handler(Socket socket) throws IOException {
        byte[] bytes = new byte[1024];
        InputStream inputStream = socket.getInputStream();
        //循环读出一次传过来的所有字节
        while (true) {
            int read = inputStream.read(bytes);
            if (read != -1) {
                System.out.println(new String(bytes, 0, read));
            } else {
                break;
            }

        }
    }
}

打上断点,调试运行程序
在这里插入图片描述
下一步,可以看到程序阻塞在socket的accept方法,等待连接进来
在这里插入图片描述
accept方法也详细说明了阻塞知道一个连接建立
在这里插入图片描述
用先前安装好的netcat作为客户端发起连接,可以看到程序取消阻塞,执行下一步
在这里插入图片描述
一直点击下一步,来到下图,因为客户端没有发数据过来,所以read方法又阻塞
在这里插入图片描述
InputStream的read方法注释
在这里插入图片描述
在nc命令端输入数据,就会传送到服务端
在这里插入图片描述
当服务器接收完数据之后,只要客户端还保持连接,read就不会等于-1,又阻塞在read方法等待客户端的数据
在这里插入图片描述
还是read注释:如果socket流关闭了read方法就会返回-1
在这里插入图片描述
现在我们来新开一个客户端连接同样的端口,可以发现由于程序阻塞在read方法,并没有接收到新客户端的连接
在这里插入图片描述
在新客户端发的消息服务器理所当然也没有接收,因为服务器当是单线程的,正在阻塞等待旧客户端的数据过来
在这里插入图片描述
那为什么第二个连接还在等待连接呢,现在关闭第一个客户端连接,发现服务器出错了,原因是客户端连接断开->stream退出,服务器的socket并没有拿到输入流,所以抛出异常
在这里插入图片描述
下面将代码完善一下,在客户端输入结束字符让服务器结束本次socket的连接,这样就不会抛出异常了

    private static void handler(Socket socket) throws IOException {
        byte[] bytes = new byte[1024];
        InputStream inputStream = socket.getInputStream();
        while (true) {
            int read = inputStream.read(bytes);
            String msg = new String(bytes, 0, read);
            if("end\n".equals(msg)) break;
            if (read != -1) {
                System.out.println(new String(bytes, 0, read));
            } else {
                break;
            }

        }
    }

可以看到客户端自己结束后,刚阻塞的新连接也连接成功了
在这里插入图片描述 在这里插入图片描述

线程池实现的BIO

每有一次客户端的连接进来,就会在 线 程 池 \color{red}{线程池} 线分配一个线程来执行这个连接,从下图可以看到红色的虚线是请求服务器并且分配线程,建立连接后双方就可以互相通信(黑色实线)
在这里插入图片描述

代码实现
public class ServerThreadBio {
    public static void main(String[] args) throws IOException {
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        //监听9000端口
        ServerSocket serverSocket = new ServerSocket(8000);
        while (true) {
            //未有连接,阻塞
            final Socket socket = serverSocket.accept();
            System.out.println("一个新的连接进来");

            newCachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        handler(socket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });


        }
    }

    private static void handler(Socket socket) throws IOException {
        try{
            byte[] bytes = new byte[1024];
            InputStream inputStream = socket.getInputStream();
            while (true) {
                int read = inputStream.read(bytes);
                if (read != -1) {
                    System.out.println(new String(bytes, 0, read));
                } else {
                    break;
                }

            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            socket.close();
        }

    }
}

可以看到服务器能同时处理两个客户端的连接请求的数据了
在这里插入图片描述
可以看到线程池有两个线程 Running
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值