BIO

Netty 是一个利用 Java 的高级网络的能力,隐藏了Java背后的复杂性然后提供了一个易于使用的 API 的客户端/服务器框架。

  • 高性能

  • 扩展性强

  • 在网络发展初期,需要花很多时间来学习 socket 的复杂,寻址等等,在 C socket 库上进行编码,并需要在不同的操作系统上做不同的处理。

  • Java 早期版本(1995-2002)介绍了足够的面向对象的糖衣来隐藏一些复杂性,但实现复杂的客户端-服务器协议仍然需要大量的样板代码(和进行大量的监视才能确保他们是对的)。

BIO

public static void main(String[] args) throws Exception {
    //1.ServerSocket 创建并监听端口的连接请求
    ServerSocket serverSocket = new ServerSocket(888);
    //2.accept() 调用阻塞,直到一个连接被建立了。返回一个新的 Socket 用来处理 客户端和服务端的交互
    Socket clientSocket = serverSocket.accept();
    //3.流被创建用于处理 socket 的输入和输出数据。BufferedReader 读取从字符输入流里面的文本。PrintWriter 打印格式化展示的对象读到本文输出流
    InputStream inputStream = clientSocket.getInputStream();
    OutputStream outputStream = clientSocket.getOutputStream();
    //4.处理循环开始 readLine() 阻塞,读取字符串直到最后是换行或者输入终止。
    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
    PrintWriter pw = new PrintWriter(outputStream);
    //5.如果客户端发送的是“Done”处理循环退出
    String request,response;
    while ((request = br.readLine()) != null){
        if("Done".equals(request)){
            break;
        }
        //6.执行方法处理请求,返回服务器的响应
        response = "服务器收到消息:" + request;
        //7.响应发回客户端
        pw.println(response);
    }//8.处理循环继续

}

这段代码限制每次只能处理一个连接。为了实现多个并行的客户端我们需要分配一个新的 Thread 给每个新的客户端 Socket(当然需要更多的代码)。但考虑使用这种方法来支持大量的同步,长连接。在任何时间点多线程可能处于休眠状态,等待输入或输出数据。这很容易使得资源的大量浪费,对性能产生负面影响

BIO实现多人聊天

原生 socket 库同时也包含了非阻塞 I/O 的功能。这使我们能够确定任何一个 socket 中是否有数据准备读或写。我们还可以设置标志,因为读/写调用如果没有数据立即返回;就是说,如果一个阻塞被调用后就会一直阻塞,直到处理完成。

  • serverSocket.accept(); 会等待一个新的socket客户端连接

  • BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

    br.readLine() 这里会等待客户端或者服务端响应消息

阻塞的同时需要处理其他的业务,那么就需要开启新的线程去处理业务

服务端

public class MyServerSocket {
    //连接的客户端
    private static Set<Socket> socketSet = new HashSet<>();

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(889);
        int index = 0;
        while(true){
            index ++ ;
            //这里会阻塞住,
            Socket socket = serverSocket.accept();
            socketSet.add(socket);

            //对每个socket的输入都开启一个线程进行监听
            new Thread(() ->{
                try{
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    //监听客户端的请求参数
                    while(true){
                        try{
                            String message = bufferedReader.readLine();
                            System.out.println(Thread.currentThread().getName() + ":" + message);
                            //遍历客户端,将其中一个客户端的消息发送给其他客户端
                            for (Socket socket1 : socketSet) {
                                if(!socket1.equals(socket)){
                                    BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket1.getOutputStream()));
                                    bufferedWriter.write(Thread.currentThread().getName() + ":" + message + "\n");
                                    bufferedWriter.flush();
                                }
                            }
                        }catch (Exception e){
                            System.out.println( Thread.currentThread().getName() + "可能退出了,将它移除掉");
                            socketSet.remove(socket);
                            break;
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            },"用户" + index).start();
        }
    }
}

客户端

public class MyClientSocket {
    public static void main(String[] args) throws Exception {

        Socket socket = new Socket("127.0.0.1",889);
        new Thread(()->{
            try {
                //等待接受服务端的消息
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while(true){
                    String s = bufferedReader.readLine();
                    System.out.println( s);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        //一直等待客户端的输入
        while(true){
            BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in));
            String readLine = systemIn.readLine();
            bw.write( readLine+ "\n");
            bw.flush();
        }
    }
}
posted @ 2021-07-25 10:53  雾里看花的少年  阅读(351)  评论(0编辑  收藏  举报