实例说明

  1. 使用 BIO 模型编写一个服务器端,监听 6666 端口,当有客户端连接时,就启动一个线程与之通讯。
  2. 要求使用线程池机制改善,可以连接多个客户端。
  3. 服务器端可以接收客户端发送的数据(telnet 方式即可)。

    服务器端代码

    ```java package com.xiaomeng.netty.learnnetty.bio;

import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;

/**

  • bio *
  • @author xiaomeng
  • @date 2021-12-11 */ public class BIOServer {

    public static void main(String[] args) throws IOException {

    1. //思路
    2. //1、创建一个连接池
    3. //2、如果有客户端连接,就创建一个线程,与之通讯(单独写一个方法)
    4. //创建连接池
    5. ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
    6. //ServerSocket 是服务器端的,等待客户端的请求,监听6666端口
    7. ServerSocket serverSocket = new ServerSocket(6666);
    8. System.out.println("服务器启动了...");
    9. //服务器端随时待命
    10. while (true){
    11. System.out.println("线程信息id ="+ Thread.currentThread().getId() + ",name = "+Thread.currentThread().getName());
    12. //监听,等待客户端连接
    13. System.out.println("等待连接...");
    14. final Socket accept = serverSocket.accept();
    15. System.out.println("连接到一个客户端");
    16. //创建一个线程,与之通讯(单独写一个方法)
    17. newCachedThreadPool.execute(new Runnable() {
    18. @Override
    19. public void run() {
    20. //可以和客户端通信
    21. handler(accept);
    22. }
    23. });
    24. }

    }

    /*

    • 更客户端通信
    • @param accept */ private static void handler(Socket accept) { try {

      1. System.out.println("线程信息id ="+ Thread.currentThread().getId() + ",name = "+Thread.currentThread().getName());
      2. //获取输入流,读取客户端的数据
      3. InputStream inputStream = accept.getInputStream();
      4. byte[] bytes = new byte[1024];
      5. //循环读取客户端发送的数据
      6. while (true){
      7. System.out.println("线程信息id ="+ Thread.currentThread().getId() + ",name = "+Thread.currentThread().getName());
      8. int read = inputStream.read(bytes);
      9. if(read != -1){
      10. System.out.println(new String(bytes,0,read));
      11. }else{
      12. break;
      13. }
      14. }

      }catch (Exception e){

      1. e.printStackTrace();

      }finally {

      1. //关闭客户端的连接
      2. System.out.println("关闭客户端连接");
      3. try {
      4. accept.close();
      5. }catch (Exception e){
      6. e.printStackTrace();
      7. }

      }

      } }

```

测试

创建telnet当客户端发送数据

1、系统启用telnet功能

1)打开控制面板-程序和功能
2)启用或关闭 windows 功能
3)勾选TelNet客户端
image.png

如果没有启用功能,会报错:telnet不是内部命令

2、客户端连接服务器 ip 和端口

新建一个cmd窗口,然后输入 telnet 127.0.0.1 6666,回车
image.png

3、按 ctrl+] 回显输入内容

image.png

4、输入 send+ 发送的内容,回车

image.png

5、服务器端控制台 收到客户端发送内容,并且打印出了线程

image.png

6、再创建一个客户端,发送内容,服务端查看发送内容和 线程

image.png

总结

  1. Java BIO 就是传统的 Java I/O 编程,其相关的类和接口在 java.io。
  2. BIO(BlockingI/O):同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善(实现多个客户连接服务器)
  3. 每个请求都需要创建独立的线程,与对应的客户端进行数据 Read,业务处理,数据 Write。
  4. 当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大。
  5. 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费。