一种基于QT的C/S架构服务器实现

2022-04-29 17:59孙婧蒋浩曹斐孟景涛
计算机与网络 2022年17期
关键词:国产化测控客户端

孙婧 蒋浩 曹斐 孟景涛

摘要:目前的航空、航天测控项目中,测控软件的主要功能之一是对测控系统各分机设备进行监控,这就对服务端的密集并行处理能力提出了较高要求。C/S架构对于安全性要求较高的测控项目有着无可比拟的优势。对于测控软件后台服务端的各种服务来说,主要功能是接收客户端发送来的原始数据,进行处理,然后返回结果。这些后台服务目前运行在国产化服务器上,调用其他服务进行并行计算。针对测控项目的需求,提出了一种C/S架构的服务端设计,主要介绍了网络处理模块与任务处理模块的设计,以及程序结构和工作流程,并使用QT进行实现,可以作为航空、航天测控软件架构服务器实现的参考。

关键词:测控;客户端;服务器;国产化

中图分类号:TP319文献标志码:A文章编号:1008-1739(2022)17-52-05

0引言

在航天、航空测控领域的地面站测控系统中,站内测控软件的主要功能之一是有序地控制各分系统设备的工作参数,同时实时接收各分系统设备上报的测控数据并进行后续数据处理,这就需要测控软件与测站分系统内各类设备之间进行数据交互。这些设备的特点是设备类型繁多、接口形式复杂,但是对单个设备而言,传输的数据量不会特别大。对于测控软件后台服务端的各种服务来说,主要功能是接收客户端发送来的原始数据,进行处理,然后返回结果。这些后台服务目前运行在国产化服务器上,调用其他服务进行并行计算。对于这些后台服务来说,与其连接的客户端数量是不确定的,在某些情况下会存在高并发现象,但是在另一些情况下客户端的数据传输频率较高,但输入输出的数据量不会太大。因此需要设计保证服务器不受客户端的影响,能够做到对各个客户端均进行及时响应,从而不影响测控任务的执行。

1软件概述

目前,测控软件使用客户端—服务架构[1],在这种架构下,服务端的设计至关重要[2],为了满足上文提到的客户端的高并发连接请求及高速率的传输需求,本文设计了一种较为通用的可用于国产服务器(性能不那么高)的服务端设计及实现方案,该方案具有可动态、灵活地进行配置的优点,可以有效减少开发人员的开发时间,服务设计具备如下特点。

首先,采用线程池技术,将客户端的监听、连接及后续的数据传输、处理等过程使用线程池中的独立线程来实现[3],从而在客户端的高并发连接请求处理和高速率的传输需求之间达成取舍。其次,使用流水线结构进行数据处理,从而减少在某些特定情况下,高数据量或密集请求客户端对其他客户端的处理产生影响[4]。整个服务端基于C++及Qt进行开发实现,可以完全适配国产CPU及银河麒麟操作系统,从而满足国产化的要求。

2软件总体设计

服务端的设计主要包含网络管理及任务处理两大模块[5]。

网络处理模块:用于管理服务端的所有Socket(网络套接字),包括其监听、连接、数据传输及关闭的全过程,同时对各Socket处理线程中的数据交换进行管理。其中,数据的接收、发送由独立的线程池进行负责,使用线程事件循环来实现。在Qt中,QThread的特点是线程对象绑定到哪个QObject类上,这个QObject类的信号—槽事件循环便属于该线程,利用这个特性,便能够方便地将某个Socket的对象与想要使用的线程进行绑定[6]。

任务处理模块:主要负责服务器所有已连接的Socket客户端的收发数据处理。在某些需要进行集中计算的后台服务中,数据处理的负担很重,因此需要将数据的处理过程与网络的传输过程分开进行。在这种情况下,如果使用普通的线程池设计方法,在客户端的高并发连接请求发生并且每个连接都比较耗时,会将其他Socket客户端的响应阻塞,从而产生数据处理队列阻塞的问题。本设計采用流水线线程池来避免这个问题,其原理是将各个Socket客户端的业务操作进行细化拆分,形成比较小的颗粒度,然后在线程池中使用一个大的环形队列,在这个队列中每次只处理一个Socket客户端的一个小颗粒度单位的任务,在一个小颗粒度单位的任务完成后,这个Socket客户端的其他剩余任务被重新排列到整个环形队列的尾部,这个机制在单个客户端不处理超大数据量的情况下,可以最大限度地保证Socket客户端的整体处理时延是比较小的。

3软件业务模块设计

3.1网络处理模块设计

3.1.1程序结构设计

网络处理模块使用线程池来管理TCP服务端对所有Socket的监听、连接、数据传输及各Socket处理线程中的数据交换。主要包括客户端的接入管理线程及客户端的数据传输线程。根据当前线程池中的各个传输线程的负载,来对收到的新客户端Socket接入申请进行评估,并最终将新生成的Socket描述符传递给线程池中负载最小的传输线程中去执行后续的连接(accept)等操作,从而实现了一个精简版本的负载均衡功能。

网络处理模块合作关系如图1所示。

该模块几个类的主要功能设计如下。

CTINet_Engine类:网络处理引擎类,其基类是QObject,是整个网络处理模块的外部接口及管理类,作为网络处理模块的引擎,提供了处理线程池的动态配置(包括监听器设置、传输参数等)等功能。

CTINetListenThread类:客户端监听线程类,其基类是QObject,主要功能是创建监听线程,并使用其来接受各种客户端Socket的连接请求。当有新的客户端接入申请时,使用Qt的信号把新客户端的套接字描述符传出,由CTINet_Engine类进行负载均衡,然后选择线程池中负载最小的传输线程(CTINetTransThread)去接受该Socket的接入申请。

CTINetTransThread类:数据传输线程类,其基类是QObject,使用传输线程完成数据的传输。一个传输线程(CTINetTransThread)设计用来进行多个客户端Socket的数据接收、发送请求。

CTITcpServer类:网络通信类,其基类是QTcpServer。它的主要功能是进行Socket连接的监听工作,该类重载了QTcpServer类中的incomingConnection()方法,这个方法实现的功能是当一个Socket客户端发起连接时,其会被立即调用。在CTITcpServer类的实现中,没有定义新的网络套接字,只是将基类中的sig_newClientArrived信号触发,这个信号会把套接字描述符传递给其他线程,其他的线程使用该套接字描述符完成套接字的创建[7]。

3.1.2客户端接入设计

当某一个Socket客户端发起接入的请求时,首先会触发网络通信类(CTITcpServer)中的连接信号(sig_incomingConnection),然后使用newClientArrived信号将套接字描述符作为参数传出,在newClientArrived信号的槽函数中,网络处理引擎(CTINet_Engine)类进行负载均衡[8],然后选择线程池中负载最小的传输线程(CTINetTransThread)去接受该Socket的接入申请,然后把Socket描述符传递给数据传输线程类。使用另外一个信号sig_establishConnection将负载均衡策略确定的承接线程和Socket描述符广播给所有的传输线程对象,最后在各个传输线程对象的连接信号(sig_incomingConnection)的槽函數中,使用该套接字描述符完成套接字的创建,从而完成客户端接入过程[9]。

3.1.3数据接收设计

在成功创建了套接字以后,数据的收发都在传输线程中运行,当Socket接收到数据时,会触发数据接收事件(dataReceived),然后由其槽函数完成数据处理过程[10]。

3.1.4数据发送设计

数据发送的设计原则是:不直接使用Socket的缓存区来缓存需要发送的数据,改为使用额外的数据发送队列,在进行数据的发送处理时,每次会进行固定长度的数据缓存并顺序地发送[11]。采用这种发送方式,就可以增加缓冲区大小的检查功能,从而方便对数据进行进一步的持久化工作等。举例来说,在数据发送队列中缓存的数据量非常大(≥200 MB)时,再有数据需要发送,就可以把新进入队列的数据先缓存在硬盘中,而不是缓存在内存里,从而降低程序对内存资源的占用。

3.2任务处理模块设计

3.2.1流水线线程池设计

在传统的服务器程序设计中,为了实现多客户端的并发连接和通信,通常采用一个客户端分配一个线程的传统多线程技术,实现少量的无阻塞并发网络通信处理,这就是传统的“任务伴随者”模式[12]。

当并发的客户端较多时,采用这种设计模式,就需要为所有的客户端各开启一个线程,当开启的线程数达到几百上千时,由于国产化CPU(龙芯、飞腾等)的物理核心支持的线程规模有限,此时CPU会消耗大量的资源进行各个线程的上下文切换和环境恢复,从而使本就不如因特尔CPU的计算能力更处劣势。

为了避免出现上文中描述的情形,采用一种新的技术进行多线程的并行计算,即线程池的设计模式。在这种设计模式下,能够有效利用国产CPU(龙芯、飞腾等)的物理核心,避免频繁切换各个客户端线程的上下文。服务器软件只创建与CPU物理核心数差不多的线程,使这些线程形成一个资源池的概念,即线程池(ThreadPool)。通过将服务器所需要实现的功能进行细化颗粒的拆分,可以将服务器功能分为很多小的任务,将这些任务全部进行队列排序,并在线程池中按照先进先出(FIFO)的次序进行处理[13]。该模式的示意如图2所示。

这种模式在并发连接较大时尽可能地提高CPU的计算能力,但是由于线程数量的限制,在单位时间内处理的任务数量级是固定的,这样就有可能会将某些客户端阻塞。如果同时处理的任务都是比较耗时的任务,则所有的客户端都有可能被阻塞,无论是耗时的客户端任务还是简单的客户端任务。

本文的架构在设计之初就是为了支持高并发且允许部分大数据量连接的客户端,因此对传统的线程池技术进行了改进,使用基于线程池的流水线技术,从而实现在国产CPU下的多客户端低阻塞情况的最优线程处理。这项技术最重要的设计是:把各个客户端所产生的任务再进一步地细化处理,线程池进行队列处理时不以一个客户端的任务为一个单位,而是以任务再次细化后的个指令为一个集合,不管某个客户端缓存了多少个任务,每次队列处理时都处理相同的个指令,然后就跳转到下一个任务的指令集合去处理[14]。流水线处理示意如图3所示。

在上文描述的方法中,流水线处理机制可以实现最大限度地并行化处理所有客户端的任务请求,保证国产化CPU有限处理资源的最大化利用,从而使系统的整体吞吐量有大幅的提高[15]。同时,在这种处理架构下,可以通过配置,将优先级最高的客户端请求进行优先处理。

3.2.2程序结构设计

线程池类合作关系如图4所示。

猜你喜欢
国产化测控客户端
特大型桥梁供电系统国产化改造探讨
元器件国产化推进工作实践探索
ASM-600油站换热器的国产化改进
基于国产化ITCS的卫星导航仿真研究
《测控电路》实践教学改革探讨
县级台在突发事件报道中如何应用手机客户端
孵化垂直频道:新闻客户端新策略
基于Vanconnect的智能家居瘦客户端的设计与实现
基于现代测控技术及其应用分析
向着新航程进发——远望7号测控船首航记录