BIO编程

BIO简介说明

传统的java io,相关的类和接口在java.io包中,同步阻塞型IO模型。服务器实现模式为一个连接一个线程,即是当客户端有一个请求过来,这时服务器端就需要启动一个线程去处理。如下图所示:

BIO的缺点:由上图所示可以看出,当一个客户端请求过来,服务器都要启动一个线程,在高并发下会产生很多的线程。线程是有开销的,每个线程在服务器端需要维护。即使客户端未与服务端通讯,只要连接着,还是需要维护这个线程。bio方法在读写时,如果没有读取到信息,还会阻塞,这些都是bio模型的缺点。

BIO具体实现流程

  1. 服务器端启动一个ServerSocket,监听端口。
  2. 客户端启动一个Socket对服务器进行通讯,默认情况下服务器端需要启动一个线程与客户端建立通讯。
  3. 客户端发送请求后,服务器端如果没有响应,这时客户端会阻塞等待,或直接拒绝。
  4. 如果有响应,表示通讯建立成功,之后就可以传递数据。

BIO代码实现

用BIO模型编写服务器端,监听端口8080,有客户端连接时,启动一个线程与之通讯;这里可以采用线程池创建线程,服务器端可以接收客户端发送的数据。

服务器端

@Slf4j
public class BIOServer {
    public static void main(String[] args) throws IOException {
        //服务端负责创建线程的线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        ServerSocket serverSocket = new ServerSocket(8080);
        log.info("服务器端启动了...");
        //这里死循环,这样可以处理多个客户端的请求,每循环一次表示完成一个客户端连接
        while (true) {
            final Socket socket = serverSocket.accept();
            //客户端与服务器端通讯已建立,通过线程池启动一个线程与之通讯
            threadPool.execute(()->{
                handler(socket);
            });
        }
    }
    //与客户端具体的通讯方法
    private static void handler(Socket socket) {
        log.info("线程信息:{}",Thread.currentThread().getName());
        try {
            byte[] bytes = new byte[1024];
            InputStream inputStream = socket.getInputStream();
            while (true) {
                int len = inputStream.read(bytes);
                if (len != -1) {
                    log.info("客户端传递过来的信息为:{}",new String(bytes,0,len));
                } else {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

打开cmd窗口,通过输入:telnet 127.0.0.1 8080   连接到服务器端

此时窗口状态为如下所示:

idea控制台中输出如下

19:47:03.639 [main] INFO com.dingmb.bio.server.BIOServer - 服务器端启动了...
19:47:13.071 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 线程信息:pool-1-thread-1

在cmd窗口中:按Ctrl+] 键   窗口显示如下所示

通过send命令发送信息到服务器端

此时控制台显示如下:

19:47:03.639 [main] INFO com.dingmb.bio.server.BIOServer - 服务器端启动了...
19:47:13.071 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 线程信息:pool-1-thread-1
19:50:06.957 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 客户端传递过来的信息为:hello001
19:50:14.758 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 客户端传递过来的信息为:hello002

再开一个cmd窗口,通过 telnet 127.0.0.1 8080 连接服务端,服务端新生成一个线程处理这个客户端的请求。

19:47:03.639 [main] INFO com.dingmb.bio.server.BIOServer - 服务器端启动了...
19:47:13.071 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 线程信息:pool-1-thread-1
19:50:06.957 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 客户端传递过来的信息为:hello001
19:50:14.758 [pool-1-thread-1] INFO com.dingmb.bio.server.BIOServer - 客户端传递过来的信息为:hello002
19:52:38.686 [pool-1-thread-2] INFO com.dingmb.bio.server.BIOServer - 线程信息:pool-1-thread-2

客户端2,发送数据

这时线程池分配的第二个线程处理这个请求,这里证明了每个客户端过来,服务端都会新分配一个新线程来建立通讯。

阻塞说明

服务器端启动后   serverSocket.accept()   这个方法会阻塞在这里,一个客户端过来,阻塞结束,开启一个线程与之通讯,由于死循环,会再到accept()方法,再阻塞等待下一个客户端请求。

客户端连接后 inputStream.read(bytes) 这个方法会导致阻塞在这里。直到客户端发送数据过来了,这时阻塞结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值