BlockingIO +thread-per-connection的网络服务器设计方案
1、 前言
在 java1.4引入 NIO之前,网络服务器的典型实现方案是采用阻塞 IO+多线程模型,后来出现了非阻塞 IO( NIO),常用的实现方案则变成 NIO+Reactor模式,还有 NIO+proactor模式。本文主要是介绍阻塞 IO+多线程模型,虽然该方案有很多缺点,但此处还对此进行介绍的原因是为后面进一步介绍基于 NIO的方案做准备,毕竟研究一种新的方案时,只有知道它出现之前的老的方案的缺点后,才能对新的方案理解的更深。
2、 TCP通信过程
面向连接的 TCP 协议可以在多个通信端点之间可靠的进行数据传递,这个过程涉及到两个角色,一个是被动( passive )角色(服务器),一个是主动 (active) 角色(客户端)。服务器在一个端点被动的等待其他端点来连接,而客户端则主动的去连接服务端。以下是交互过程:
3、BlockingIO + thread-per-connection设计方案
3.1 通信体系示例
上面是一个典型的网络服务器通信体系。一个 web 服务器会同时被多个客户端并发的访问,每次访问中,客户端与服务器的通信过程分为以下几个步骤:
- 用户在客户端的浏览器中打开一个 URL,浏览器发送请求给服务器
- 服务器收到请求后,解析请求
- 服务器对请求进行处理
- 服务器将结果发给客户端
3.2 BlockingIO + thread-per-connection 架构方案
- Thread-per-connection:顾名思义,为每个连接分配一个线程。多个客户端并发的向服务端发起请求,同步的 Acceptor通过 TCP三次握手后,每接受一个客户端的 connection,就为该 connection分配一个线程,然后由该线程处理该客户端的请求。这样就实现了多个线程并发处理多个客户端请求的目的。
- BlockingIO:为什么是阻塞?如果客户端没有 connect请求,则服务端监听客户端连接的线程会一致等待连接,阻塞在 accept中;连接成功后,如果客户端一直没有发起请求,则负责处理该客户端请求的线程会一直阻塞在等待读取请求数据中;服务端向客户端回写数据的时候,也可能会被阻塞直到响应数据发送完毕。
使用该方案有以下缺点:
- 由于服务端需要为每个已连接的客户端分配一个线程,所以服务端线程的数量与已连接的客户端的数量是成线性正比关系的,譬如有 1000个客户端并发访问,而且是长连接,则服务端会启动 1000个线程。而每个线程是需要分配一定大小的堆栈空间的,所以在高并发的情况下,就会导致服务器资源耗尽。当然也可以采用线程池来处理,以控制线程的数量,但在高并发的情况下,当线程池的线程都分配完后,就无法再响应后面的客户端请求了,所以可伸缩性比较差。
- 多个线程之间的上下文切换也是浪费 CPU时间的,尤其是存在大量空闲连接的情况下,切换线程上下文完全是没有必要的
- 由于存在多线程,所以在共享资源的访问上就要求开发人员做好同步控制,增加了实现的复杂度。
4、代码示例
4.1 java Io的几个关键概念
- ServerSocket:服务端监听套接字,创建时需要指定端口号,譬如: new ServerSocket(9090),表示建立了一个监听 9090端口的套接字对象。该对象通过 accept方法监听客户端的连接请求,会阻塞直到建立一个连接,并返回已连接的套接字。
- Socket:客户端需要建立该套接字与服务端进行通信,创建时需要指定服务器的地址和端口,譬如: new Socket(InetAddress.getByName("localhost"), 9090)。利用该对象的方法 getOutputStream()和 getInputStream()可以分别获得向 Socket读写数据的输入/输出流
- 阻塞读 : 数据在不超过指定的长度的时候有多少读多少,没有数据就会一直等待
- 阻塞写:会一致阻塞,直到将所有数据写完
4.2 code
注:所有代码只用来作为原理的进一步阐述,不能用于生产环境
模拟以下场景:客户端向服务端发送 nice to meet you 信息,然后服务端响应客户端,发送 Nice to meet you too 。
服务端代码如下(采用线程池) package iothreadpool; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 服务端 * @author jason * */ public class IoServer implements Runnable{ ExecutorService threadPool = Executors.newCachedThreadPool(); @Override public void run() { try{ //建立服务端监听套接字,绑定的端口号是9090 ServerSocket serverSocket = new ServerSocket(9090); while(true){ //监听客户端的的连接请求,会一直阻塞直到建立一个连接,并返回已连接的套接字 Socket socket = serverSocket.accept(); //为每一个连接从线程池分配一个线程 threadPool.execute(new Handler(socket)); } }catch(Exception e){ e.printStackTrace(); } } //处理线程 class Handler implements Runnable{ private Socket socket; Handler(Socket s){ this.socket = s; } @Override public void run() { try{ byte[] input = new byte[1024]; //读取客户端的请求数据,如果没有数据,会一直阻塞 socket.getInputStream().read(input); //数据处理 System.out.println(new String(input)); //发送响应 socket.getOutputStream().write("nice to meet you too".getBytes()); }catch(Exception e){ e.printStackTrace(); } } } //启动服务端 public static void main(String[] args){ new Thread(new IoServer()).start(); } }
客户端代码如下: package io; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; public class IoClient{ public static void main(String[] args) throws UnknownHostException, IOException{ byte[] input = new byte[1024]; //连接服务端 Socket socket = new Socket(InetAddress.getByName("localhost"), 9090); //发送请求 socket.getOutputStream().write("nice to meet you".getBytes()); //读取响应数据 socket.getInputStream().read(input); System.out.println(new String(input)); //关闭连接 socket.close(); } }
5、总结
本文对 BlockingIO + thread-per-connection 的网路服务器设计方案进行了描述,并分析了该方案的缺点(注:如果客户端的连接数不是很大,则采用该方案是合适的),在下一篇 blog 中将分析 NIO+reactor 模式的网路服务器设计方案
本文为原创,转载请注明出处
相关推荐
RT-Thread 3.1.3是这个操作系统的一个版本,它支持多线程、内存管理、网络协议栈、文件系统等多种功能,具备良好的可扩展性和移植性。在STM32F103上运行RT-Thread,可以实现复杂任务的并发执行和时间敏感的操作,...
RT-Thread是一款轻量级、高可靠性的实时操作系统(RTOS),专为物联网设备和嵌入式系统设计。在本实验中,我们将深入探讨如何将RT-Thread与STM32F系列微控制器结合,创建一个稳定运行的工程源码实例。 首先,了解...
+---5-教学设计-成品模板 | +---6-说课稿-成品模板 | +---7-人才培养方案-成品模板 | +-- -8-课程标准 | \---9-教学能力大赛工作总结 +++++++++++++ ++++++++++++++++++ 历年收集的课程思政、课程建设、教材教法...
+---2005-2019国社科中标标书(51份) | \---申请书 | +---活页 +---国社科中期评估 | +---国社科开题 | +---国社科标书各部分写作套路 | | | \---2023年填写模板 | + ---国社科申报技巧 | +---国社科结题 ...
在这个“STM32标准库+rt-thread+freemodbus主机移植”项目中,开发者将FreeModbus主站功能整合到了基于STM32的标准库和RT-Thread系统之上。这通常涉及以下步骤: 1. **环境搭建**:首先,需要安装Keil IDE,并配置...
总的来说,"stm32f103vet6+rt-thread lwip"项目展示了如何在STM32平台上构建一个基于RTOS的网络服务器系统,利用LwIP实现网络通信功能。这个项目对于学习嵌入式网络编程、理解RTOS与硬件的交互以及微控制器上的TCP/...
基于STM32F103RE+RT-Thread RTOS的新冠肺炎疫情监控平台,使用RT-Thread Studio开发,ESP8266作为联网设备,获取疫情API数据,cJSON数据解析,LCD数据展示。
【基于i.MX RT1050+RT-Thread云接入demo】 本示例主要介绍如何在基于NXP i.MX RT1050微处理器的平台上实现RT-Thread实时操作系统与云端服务的连接,从而实现物联网设备的远程控制、数据上传等功能。RT-Thread是一个...
STM32+RT-Thread+AD5676R+ec11+OLED+u8g2 波形发生器是一种集成了多种技术的高级电子设备,它主要用于生成各种模拟信号,适用于教学、测试和研发等领域。这个项目的核心是STM32微控制器,它是一个基于ARM Cortex-M...
基于io_uring/epoll/kqueue 的 Runtime,Monoio目标是在兼顾平台兼容性的情况下,做最高效、性能最优的 thread-per-core Rust Runtime。
一个基于 io_uring/epoll/kqueue 的 Runtime,Monoio 目标是在兼顾平台兼容性的情况下,做最高效、性能最优的 thread-per-core Rust Runtime。
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,由意法半导体(STMicroelectronics)...通过深入研究这些资料,你可以更详细地了解如何将STM32、RT-Thread和W25X16整合在一起,实现高效可靠的文件存储解决方案。
1、移植了FreeModbus1.5及RT-Thread1.1.1至STM32 2、开发平台支持Eclipse、Keil、IAR 3、可在Eclipse采用EGIT插件进行版本管理 4、支持Modbus RTU(ASCII未测试) 详细说明可参见:...
UM1010-RT-Thread-Web 服务器(WebNet)用户手册1是关于RT-Thread操作系统中的Web服务器实现——WebNet的详细指南。WebNet是RT-Thread团队自主研发的一款基于HTTP协议的轻量级Web服务器,适用于嵌入式设备与HTTP客户端...
1、移植并修改了 FreeModbus1.5 及 RT-Thread1.2.2 至 STM32 ,新增主机功能 2、开发平台支持Eclipse、Keil、IAR 4、支持 Modbus RTU 5、Modbus主机 支持所有常用功能(寄存器、线圈、离散输入) 6、目前的Modbus...
在Java多线程编程中,Thread-per-Message模式是一种常见的并发处理策略。这种模式的核心思想是为每个消息或任务创建一个新的线程来处理,使得消息的发送者和处理者不在同一个线程上下文中运行,从而实现任务的异步...
if (EXCEPTION_BREAKPOINT == per->ExceptionCode) { // 判断断点地址是否为WriteFile()API地址 if (g_pfWriteFile == per->ExceptionAddress) { WriteProcessMemory(g_cpdi.hProcess, g_...
这个项目对于学习网络编程、C#编程以及客户端-服务器通信机制具有很高的参考价值。下面将详细介绍该项目中的关键知识点。 1. **C#语言**: C#是一种面向对象的编程语言,由微软开发,主要用于Windows平台的应用...
| +---phpMyAdmin (phpMyAdmin 数据库管理系统) | +---Apache2 (Apache2 程序目录) | | | +---conf\httpd.conf (Apache 配置文件) | +---MySQL5 (MySQL 程序目录) | | | +---my.ini (MySQL 配置文件...
7. **IO流**:在读取配置文件、日志记录或者与外部系统交互时,Java的IO流会发挥重要作用。 8. **设计模式**:除了MVC,可能还会运用到工厂模式(Factory)、单例模式(Singleton)、策略模式(Strategy)等设计...