一个简单的伪异步IO程序

为了解决同步阻塞IO面临的一个请求需要一个线程处理的问题,后来有人对它的线程模型进行了优化,通过一个线程池来处理多个客户端的请求接入,形成客户端个数M:线程池最大线程数N的比例关系,其中M可以远大于N。通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量请求并发接入导致线程耗尽。
下面我们通过一个示例来说明

服务端代码

TimeServer

public class TimeServer {

    public static void main(String[] args) throws IOException {
        ServerSocket server = null;
        try {
            // 如果端口未被占用且合法则创建成功
            server = new ServerSocket(8080);
            Socket socket = null;
            // 创建线程池
            TimeServerHandlerExecutePool executePool = new TimeServerHandlerExecutePool(50,10000);
            // 通过无限循环来监听客户端连接,如果没有客户端接入,主线程阻塞在accept操作上
            while (true) {
                socket = server.accept();
                // 将请求任务丢到线程池中进行处理
                executePool.execute(new TimeServerHandler(socket));
            }
        } catch (Exception e) {
            System.out.println("创建serverSocket失败,端口:" + 8080);
            e.printStackTrace();
        } finally {
            System.out.println("The time server close");
            if (server != null) {
                server.close();
            }
        }
    }
}

服务端创建一个ServerSocket,然后通过无限循环的方式来监听客户端连接,如果没有客户端接入,则主线程会阻塞在accept操作上。定义一个线程池用来处理客户端请求任务,当有客户端连接接入后,将socket组装成TimeServerHandler,这是个Runnable,丢到线程池中进行处理
TimeServerHandler

public class TimeServerHandler implements Runnable {

    private Socket socket;

    public TimeServerHandler(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        BufferedReader in = null;
        PrintWriter out = null;
        try {
            in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            out = new PrintWriter(this.socket.getOutputStream(), true);
            String currentTime;
            String body;
            while (true) {
                // ★ 读取一行,如果读到输入流尾部,则返回值为null,退出循环
                body = in.readLine();
                if (null == body) {
                    break;
                }
                System.out.println("The time server receive order : " + body);
                // 如果读到了非空值,对内容进行判断,如果请求消息为查询时间的指令 QUERY TIME ORDER,则获取当前系统时间
                // 通过PrintWriter的println函数发送给客户端,然后退出循环
                if ("QUERY TIME ORDER".equalsIgnoreCase(body)) {
                    currentTime = new Date(System.currentTimeMillis()).toString();
                } else {
                    currentTime = "BAD ORDER";
                }
                // ★ 通过printWriter发送给客户端
                out.println(currentTime);
            }
        } catch (IOException e) {
            System.out.println("exception");
            e.printStackTrace();
            // 释放输入流
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            // 释放输出流
            if (out != null) {
                out.close();
            }
            // 释放socket套接字句柄资源
            if (this.socket != null) {
                try {
                    this.socket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}

TimeServerHandlerExecutePool

public class TimeServerHandlerExecutePool {

    private ExecutorService executorService;

    public TimeServerHandlerExecutePool(int maxPoolSize, int queueSize) {
        this.executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), maxPoolSize,
                120L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize));
    }

    public void execute(Runnable task) {
        this.executorService.execute(task);
    }
}

客户端代码

TimeClient

public class TimeClient {

    public static void main(String[] args) {
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try {
            //
            socket = new Socket("127.0.0.1", 8080);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            // ★ 通过PrintWriter向服务端发送 QUERY TIME ORDER 指令
            out.println("QUERY TIME ORDER");
            System.out.println("send order to server succeed.");
            // ★ 通过BufferedReader读取响应并打印
            String response = in.readLine();
            System.out.println("Now is : " + response);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放输入流
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            // 释放输出流
            if (out != null) {
                out.close();
            }
            // 释放socket套接字句柄资源
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}

分别执行服务端和客户端,执行结果如下:
服务端执行结果:

The time server receive order : QUERY TIME ORDER

客户端执行结果:

send order to server succeed.
Now is : Sun Jul 19 16:48:30 CST 2020

到此伪异步IO的示例程序讲解完毕

Talk is cheap , show me the picture
最后通过一张图来说明伪异步IO的通信模型
在这里插入图片描述

总结

由于线程池是有界的,无论客户端并发连接数多大,都不会导致线程个数过于膨胀或者内存溢出,相比传统的BIO是一种改良。但仍然无法解决同步IO导致的通信线程阻塞问题

参考资料

  • 《Netty权威指南》第二版 by 李林锋
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 C++ Crow Asio 应用程序示例,它基于异步 IO 编写,并使用 Boost 库进行编译: ```c++ #include "crow_all.h" #include <boost/asio.hpp> #include <memory> int main() { // 创建一个 io_context 对象 auto io = std::make_shared<boost::asio::io_context>(); // 创建一个 Crow 应用程序对象,并将 io_context 对象传递给它 crow::SimpleApp app; CROW_ROUTE(app, "/")([](){ return "Hello, World!"; }); // 创建一个 TCP 服务器对象,并将应用程序对象和 io_context 对象传递给它 boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 8080); boost::asio::ip::tcp::acceptor acceptor(*io, endpoint); acceptor.listen(); // 开始监听客户端请求,并启动 io_context 对象的事件循环 boost::asio::spawn(acceptor.get_executor(), [&](boost::asio::yield_context yield){ while(true){ boost::system::error_code ec; boost::asio::ip::tcp::socket socket(*io); acceptor.async_accept(socket, yield[ec]); if(!ec){ boost::asio::spawn(socket.get_executor(), [&](boost::asio::yield_context yield){ try{ // 处理客户端请求 auto conn = std::make_shared<crow::Connection>(app, std::move(socket)); conn->start(); }catch(const std::exception& e){ std::cerr << "Exception in connection: " << e.what() << std::endl; } }); } } }); // 启动应用程序的主循环 app.port(8080).run(); // 启动 io_context 对象的事件循环 io->run(); return 0; } ``` 这个程序创建了一个简单的 Crow 应用程序,监听 8080 端口,并在客户端请求时返回 "Hello, World!"。其中 `boost::asio::spawn()` 方法用于在异步 IO 模式下处理客户端请求,同时启动了 `io_context` 对象的事件循环。在程序运行时,需要在终端中使用编译器和 Boost 库进行编译,并执行编译后的可执行文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值