Reactor 模式和 Java NIO

概述

本文先从基本的 Socket 编程模式说起,介绍了 Java 传统的同步阻塞 IO 网络编程的基本实现,以及存在的性能问题,从而引出 Reactor 设计模式,最后通过 Java NIO 给出单 Reactor 单线程的实现方案。

Socket 编程模式

Unix 有几个统一性的理念或象征,并塑造了它的 API 及由此形成的开发风格。其中最重要的一点应当是“一切皆文件”模型及在此基础上建立的管道概念。

在 Unix/Linux 环境下,网络中的进程通过 Socket 进行通信,Socket 本质上也是一种特殊的文件,可以按照“打开,读写,关闭”的模式来操作。Socket 编程的基本模式如图 1 所示:

  1. 创建 socket:本质上就是创建一个文件,每个文件都有一个整型的文件描述符(fd)来指代这个文件;

  2. 绑定端口:一台服务器可以同时运行多个不同的应用,在 TCP/IP 协议下通过端口进行区分,因此接下来需要绑定端口,所有连接到该端口的请求都会被我们的服务处理;

  3. 监听端口:执行创建 socket 和bind之后,socket 还处于closed状态,不对外监听,需要调用listen方法,让 socket 进入被动监听状态;其 API 定义如下:

int listen(int sockfd, int backlog);
// 在TCP协议下,建立连接需要完成三次握手,当连接建立完成后会先放到一个连接队列,backlog就是指定这个队列的大小。
  1. 接收请求:通过调用accept()从已完成连接的队列中拿到连接进行处理,如果没有连接则调用会被阻塞。

基于同步阻塞 IO 的 Java Socket 编程

下面介绍在 Java 语言下如何完成 Socket 通信。传统的 Java Socket 编程模式使用同步阻塞 IO,如图 2 所示。

服务端通过new ServerSocket(端口号)完成了绑定端口和监听端口的工作,接着循环调用 accept() 方法获取客户端请求(如果没有新的请求,程序就会阻塞),并为每一个客户端请求创建一个处理线程,避免因为主线程正在处理请求而无法响应其他连接。具体实现代码如下:

import java.io.*;import java.net.ServerSocket;import java.net.Socket;
public class Server {
      public static void main(String[] args) {
          try {
              // 绑定并监听端口            ServerSocket server = new ServerSocket(5566);            Socket client;            while (!Thread.interrupted()) {
                  // 接受请求,没有请求会阻塞                client = server.accept();                new Thread(new Handler(client)).start();            }        } catch (IOException e) {
              e.printStackTrace();        }    }
    static class Handler implements Runnable {
          final Socket client;
        public Handler(Socket client) {
              this.client = client;        }
        @Override        public void run() {
              try {
                  BufferedReader reader = new BufferedReader(                        new InputStreamReader(client.getInputStream()));                // 接收客户端发送的内容                String line;                PrintWriter writer = new PrintWriter(                        new OutputStreamWriter(client.getOutputStream()));                // 客户端连接未关闭前,readLine返回值不为null,没有数据时会阻塞                while ((line = reader.readLine()) != null) {
                      writer.println("你输入的是:" + line);                    writer.flush();
                    // 通过约定特定输入,结束通讯                    if ("end".equals(line)) {
                          break;                    }                }                writer.close();                reader.close();                client.close();            } catch (IOException e) {
                  e.printStackTrace();            }</
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾听铃的声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值