【Netty学习】 阻塞式IO

  • Post author:
  • Post category:其他




【Netty学习】 阻塞式IO

Netty学习第一弹,先从简单的阻塞式IO说起。

本文主要介绍传统阻塞式socket通信,代码可分为Server端 和 Client端


Server端代码

package socket;

public class ServerBoot {
    private static final int PORT = 8080;

    public static void main(String[] args) {
        Server server = new Server(PORT);
        server.start();
    }
}
package socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    private ServerSocket serverSocket;
    public Server(int port) {
        try {
            //创建一个ServerSocket
            this.serverSocket = new ServerSocket(port);
            System.out.println("服务端启动成功,端口:" + port);
        }catch (IOException e){
            System.out.println("服务端启动失败");
        }
    }

    public void start(){
        //启动一个线程监听消息
        new Thread(()->{
            dostart();
        }).start();
    }

    private void dostart(){
        while (true){
            try {
                //收到来自客户端的socket消息,将其交给ClientHandler处理
                Socket client = serverSocket.accept();
                new ClientHandler(client).start();
            } catch (IOException e) {
                System.out.println("服务端异常");
                e.printStackTrace();
            }
        }
    }
}
package socket;

import java.io.InputStream;
import java.net.Socket;
//处理客户端
public class ClientHandler {
    public  static final int MAX_DATA_LEN = 1024;
    private final Socket socket;
    public ClientHandler(Socket client) {
        this.socket = client;
    }
    public void start(){
        System.out.println("新客户端接入:");
        new Thread(()->{
            doStart();
        }).start();
    }

    private void doStart(){
        try {
            InputStream inputStream = socket.getInputStream();
            while (true){
                byte[] data = new byte[MAX_DATA_LEN];
                int len;
                //读取消息
                while ((len = inputStream.read(data)) != -1){
                    String message = new String(data, 0, len);
                    System.out.println("客户端传来消息:" + message);
                    //消息写回客户端
                    socket.getOutputStream().write(data);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


Client

代码

public class Client {
    private static final String HOST = "127.0.0.1";
    private static final int PORT = 8080;
    private static final int SLEEP_TIME = 1000;

    public static void main(String[] args) throws IOException {
        final Socket socket = new Socket(HOST,PORT);     
        new Thread(()->{
            System.out.printf("客户端启动成功\n");
            while (true){
                try {
                    String message = "hello world";
                    System.out.println("客户端发送数据:" + message);
                    socket.getOutputStream().write(message.getBytes());
                    Sleep();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private static void Sleep(){
        try {
            Thread.sleep(SLEEP_TIME);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

阻塞式的通信很简单。

1、在服务端创建一个ServerSocket监听客户端消息

2、一旦收到消息,创建ClientHandler,将来自client的socket交给clientHandler处理

3、ClientHandler会创建一个线程去处理消息,保证serverSocket.accept() 不会被阻塞。

总之就是,客户端发送一个请求,建立Socket长连接, 服务端创建一个线程去处理该请求。

在并发量高的情况下,比如同时有50000个来自客户端的长连接请求,那么服务端就要创建50000个线程来维持这些连接。看似很美好,实则是

真的太占用内存了

,远远不能满足高并发的需求。

其实仔细想想,维持这么多的连接是很浪费资源的,说的俗一点,就是**“占着茅坑不拉屎”**。某些socket资源被客户端占用了,但是并没有进行消息传递,而是处于空闲状态。

有兴趣的童鞋可以试一下以下代码,打开你的任务管理器,观察下你的机器内存使用情况。

package socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class Client {
    private static final String HOST = "127.0.0.1";
    private static final int PORT = 8080;
    private static final int SLEEP_TIME = 1000;

    public static void main(String[] args) throws IOException {
        final Socket socket = new Socket(HOST,PORT);

        for(int i = 0; i < 100000; i++){
            new Thread(()->{
                System.out.printf("客户端启动成功\n");
                while (true){
                    try {
                        String message = "hello world";
                        System.out.println("客户端发送数据:" + message);
                        socket.getOutputStream().write(message.getBytes());
                        Sleep();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            System.out.println(i);
        }

//        new Thread(()->{
//            try {
//                InputStream inputStream = socket.getInputStream();
//                while (true){
//                    byte[] data = new byte[1024];
//                    int len;
//                    while ((len = inputStream.read(data)) != -1){
//                        String message = new String(data, 0, len);
//                        System.out.println("服务端传来消息:" + message);
//                    }
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }).start();

    }

    private static void Sleep(){
        try {
            Thread.sleep(SLEEP_TIME);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}



版权声明:本文为e31006原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。