基于twisted框架的脑电波数据传输的服务器的制作方法

文档序号:15049763发布日期:2018-07-27 23:59阅读:216来源:国知局

本发明涉及网络编程领域,是一种基于脑电波数据传输的服务器。



背景技术:

当今社会,对脑电波的研究日益广泛。通过对人脑的脑电波进行研究分析,可以得知人精神状态和生理状态,进而可以得知人的情感和健康状态。在分析人情感方面,脑电波可以得知青少年是否早恋、犯罪嫌疑人是否说谎等。在分析病人健康方面,脑电波是诊断癫痫的必要条件,是研究睡眠最客观的依据。总的来说,脑电波的研究与应用都在日益增强。

实际应用中,可以利用服务器技术对采集到的脑电波数据进行解析和存储,可以使得脑电波的应用进一步增强。比如,当工作人员出现打瞌睡或者反应迟钝现象时,其相应的脑电波的某些参数低于(或高于)阈值,从而发出警告,以避免事故的产生;与脑电波相关症状(例如睡眠不足导致记忆力衰退)的脑电波数据进行入库管理,以及对历史数据的综合分析,加深对症状规律的认知。基于脑电波通信的服务器技术具有很好的研究与实用价值。

从终端设备获取的脑电波数据包括了脑电波原始波形数据与统计数据(例如alpha、beta、gamma等参数)。终端设备通过tcp/ip通信,把脑电波数据打包发送到服务器。服务器接收tcp报文、解析数据、保存到数据库以备后续查询。同时,服务器还应支持在线客户端,通过服务器转发设备终端的实时数据或者从数据库中读取历史数据,以供客户端软件图形化显示、分析之用。



技术实现要素:

为了克服现有的服务器的兼容性、会话性和扩展性较差的不足,本发明提供一种兼容性、会话性和扩展性较好的基于twisted框架的脑电波数据传输的服务器,本发明采用twisted框架进行设计,以增强服务器的有效性和可靠性。

本发明所采用的技术方案为:

一种基于twisted框架的脑电波数据传输的服务器,所述服务器为一种传输、转发、保存脑电波数据的服务器端,所述服务端包括通信模块、脑电波数据解析模块与数据库模块;

所述通信模块中实例化两个工厂对象为devfactory和userfactory,分别用于管理设备devprotocol、用户userprotocol与服务器之间的通信协议;devprotocol协议实现设备的登录与注销、上报数据的解析、一条完整记录的数据库保存、以及向相关联的在线用户转发经过解析之后的数据;userprotocol协议实现用户的登录与注销、解析用户下发的命令、以及非阻塞地执行相应的命令;

用户与设备之间是多对多的关系,为了实现devprotocol和userprotocol两个协议之间能够实时获取对方在线状态和相互通信,设置了两个字典:user_dev_priv和dev_user_priv。user_dev_priv保存的是某个用户id号为key、以有控制权限的在线设备devprotocol实例列表为value的字典,也即{userid1:[设备实例1,...],…,useridx:[设备实例1,...]}。类似地,dev_user_priv保存的是某个设备id号为key、与其相关联的用户userprotocol实例列表为value的字典,也即{devid1:[用户实例1,...],…,devidy:[用户实例1,...]}。当设备连接成功或者断开时,devprotocol协议调用updateonlinedevice()函数,查询数据库,得到与该设备相关联的所有用户,然后在user_dev_priv字典中,添加/删除该设备的devprotocol实例;当用户登录/注销时,调用updateonlieuser()函数,查询数据库,得到与该用户相关联的所有设备,然后在dev_user_priv字典中,添加/删除userprotocol实例。因此,设备的devprotocol协议中,只要通过getonlineuser()函数,查询dev_user_priv字典,就得到与该设备关联的所有在线用户,以便设备转发脑电波数据;用户userprotocol协议调用getonlinedevice()函数,查询user_dev_priv字典,获得当前有控制权限的所有在线设备,实现对在线设备的控制和查询。

进一步,所述服务器接收到设备上发的脑电波数据后,触发devprotocol协议中的datareceived()事件,该事件处理包括了设备合法性认证、数据解析、解析后的完整记录保存到数据库的历史数据表中以及向有控制权限的在线用户转发数据;

脑电波数据解析是在prototrans模块中完成的,当设备与服务器建立连接之后,设备上发的数据,在devprotocol协议中,调用prototrans模块中的neurodata()函数来解析数据;接口函数prototrans.neurodata()以python字符串为输入参数,利用pyarg_parsetuple()函数,把python字符串转换为c语言字符串;调用parseneuropacket()对以字符串给出的数据报文,按照规定的协议进行解析;解析之后的数据,利用py_buildvalue()函数,构造{key:value}字典,返回到python程序中,数据解析模块采用python提供的distutils工具来生成相应的动态库文件。

再进一步,所述服务器接收到用户上发的带/不带参数命令的tcp报文,触发userprotocol协议中的datareceived()事件,该事件处理包括用户合法性认证、命令解析和执行命令;

如果接收到的命令和参数是合法的,则直接执行;如果是非法的或者参数有误,则返回错误信息;如果是查询历史数据等需要花费很长时间的命令,则采用从twisted.internet.threads导入defertothread()函数,转换成线程在后台运行,避免userprotocol协议的阻塞。

更进一步,数据库利用对象映射sqlalchemy进行操作,数据库中的表或者表中的一条记录就可以直接通过sqlalchemy操作类或者类实例来完成,通过orm中工具sqlalchemy,就可以实现对数据库添加、删除和查询;

devprotocol协议中调用数据库db模块中函数auth_dev_history()把解析后的记录插入到数据库历史数据表中。每条记录包括了以mediumint字段定义的各个统计参数和以blob字段定义的原始波形数据,其中各个统计参数以“insertinto”的方式一次性插入到历史数据表中,此时blob字段为空,然后这条记录中的原始波形数据,以“update”的方式刷新刚才“insertinto”记录中的blob字段;此时记录写到到数据库缓存内,每隔一定时间,调用mysqldb的commit()函数,把缓存中的记录,真正写入到数据库中。

devprotocol和userprotocol协议启动后,开启超时定时器。设备/用户的每次datareceived()事件会重新刷新超时定时器,当长时间没有刷新超时定时器,则认为设备/用户以及断开,软件自动触发connetionlost事件,断开tcp连接。

本发明中,设计的服务器软件采用模块化设计方法,软件采用python语言编写,具有很好的跨平台性;采用twisted非堵塞网络框架,反应器reactor用于监听服务器端口,工厂factory用于配置一些永久性配置,协议protocol用于管理网络通信;对设备上传的数据,采用c语言进行解析,解析得到的数据以字典的方式返回给python主进程,充分利用c语言的灵活性和高效性;采用mysql开源数据库,用于保存解析之后的设备统计参数和原始波形数据,以及支持用户的历史数据查询。其作用分别为:

设计的服务器采用模块化的方法实现,主要包括会话实现部分、脑电波数据解析部分、数据库部分。

会话的实现,客户端分为设备和用户两个大类,分别在模块dev和user中具体实现。用对象devfactory和userfactory分别用来管理设备和用户的客户端的连接。

在devfactory单元中,实例化协议devprotocol,并且负责devprotocol单元的管理。在此单元中,包括设备服务的初始化、设备的连接、设备的添加/删除、设备持久数据的配置以及对于设备数据库的操作。其为一个抽象工厂,核心功能是管理设备的连接事件,实例化出设备协议管理设备客户端的网络通信。

在devprotocol单元中,用于设备建立连接后的事件处理。包括设备的初始化、成功建立设备连接、设备的连接失败或者中断、设备数据的解析与保存。其主要作用是在devfactory实例化一个对象后,接手处理对象的通信。具体来说,当有设备客户端进行tcp连接请求时,devprotocol单元中调用函数connectionmade()处理此tcp连接事件,获取ip地址、端口等信息。设备建立tcp连接之后,向服务器上发数据,将触动事件datareceived()事件,进行相应的事件处理,实现数据的解析、转发和保存。具体地说,如果用户不允许接收该设备上报的数据,则直接丢弃;如果用户允许接收,则对收到的几个tcp报文进行组合和拆分,使得解析之后,得到一个完整的、包括了统计参数与原始波形数据的一条数据库记录;对解析后的数据进行合法性检查,如果在数据库设备表中找不到该序列号,则认为是非法设备,直接调用loseconnection()断开tcp连接;对合法设备,在本次连接断开之前,不再进行合法性验证,调用adddevice()函数对设备终端进行添加;调用自定义的getonlineuser()函数,获取有读取该设备权限的所有在线用户,将设备终端解析后的数据转发给各个在线用户;把解析后一条完整的统计参数和原始波形数据,保存到数据库的历史数据表dev_history中,以供后续用户查询。

上述过程中的数据解析,datareceived()事件中接收到的tcp数据报文,是以python字符串变量的形式表示。数据解析部分是在prototrans模块中完成的,此模块用c语言实现,利用c语言的灵活性和高效率,以提高协议解析的效率。接口函数prototrans.neurodata()以python字符串为输入参数,利用pyarg_parsetuple()函数,把python字符串转换为c语言字符串。调用parseneuropacket()对以字符串给出的数据报文,按照规定的协议进行解析。解析之后的数据,利用py_buildvalue()函数,构造{key:value}字典,返回到python程序中。数据解析模块,采用python提供的distutils工具来生成相应的动态库文件。具体方法为:编写setup.py脚本,其中最主要的是ext_modules=[extension(mod,sources=['prototrans.c'])]),指定了模块名和模块具体实现的c文件名,分别为prototrans和prototrans.c。分别执行pythonsetup.pybuild和pythonsetup.pyinstall命令,进行编译和安装,成功之后会生成一个动态文件prototrans.so,此模块就可以被python调用。

上述过程中的记录保存,调用数据库db模块中函数auth_dev_history()把该条记录插入到历史数据表dev_history中,此时记录写到到数据库缓存内。每隔一定时间,调用mysqldb的commit()函数,把缓存中的记录,真正写入到数据库中。每条记录包括了以mediumint字段定义的各个统计参数和以blob字段定义的原始波形数据,其中各个统计参数以“insertinto”的方式一次性插入到历史数据表中(此时blob字段为空),然后这条记录中的原始波形数据,以“update”的方式刷新刚才“insertinto”记录中的blob字段。

同样,在userfactory单元中,实例化协议userprotocol,并且负责userprotocol单元的管理。此单元包括用户服务的初始化、用户的添加/删除和对数据库中用户表的操作。在userprotocol单元中则用于管理用户的通信方面、设备数据开始/结束采集的控制、设备历史数据的查询等事件。

数据库有四张表格组成,分别为用户表、设备表、设备历史表、以及用户与设备关联表。表中存储着相应的具体信息。以用户表来说,包含用户id号、用户名、密码、ip地址、端口号和最新接入时间等信息。用户表和设备表可添加并存储客户端接入时候认证的序列号。用户设备关联表可添加关联的序列号。设备历史表则记录解析成功的设备数据。

管理员需要事先添加信息,以便后续数据库中序列号认证以及序列号互相查询。表的设计采用对象映射sqlalchemy工具,相当于实例化了数据库,可方便管理。利用sqlalchemy中的declarative_base对象,可以通过base.metadata.create_all(engine)来创建所有base派生类所对应的数据表。在引擎创建时候引入线程池,可以提高效率并且降低资源消耗。对数据库的操作通过session模块来完成。通过引擎可以创建一个session工厂,利用工厂方法实例化一个对象session,借助add、commit等方法可以完成对象的具体操作。

本发明中,考虑到会话的通信实现,设计了统一管理会话的方法;考虑到服务器与不同客户端会话的要求,将客户端抽象为设备和用户两个大类,分别用于管理和用户,且设计的服务器能满足多个客户端同时连接的要求,也即设备与用户之间是多对多的关系;设备上传的脑电波数据进行解析和格式转换,保存到数据库中,以供后续的数据分析之用;考虑到设备上电之后一直发送数据,且只发不收,服务器接收到的设备数据,那些需要保存、那些不需要保存,由用户通过信令来决定。本发明的有益效果主要体现在:

1)可移植性强,设计的服务器具有良好的跨平台性,可运行于当前主流的linux、window和ios等平台。

2)模块化设计方法让代码结构更富有层次感立体感,降低代码耦合度,便于修改与维护。

3)基于异步事件驱动的非阻塞方式,处理中不会有任何等待,可以大幅度较少时间消耗。

4)可扩展性强,利用c语言进行混编,提高了服务器处理数据的效率。

5)保密性增强,编译扩展模块的代码弥补了了python语言易读导致的保密性不强的缺点,提高代码安全性。

附图说明

图1服务器的网络框架。

图2服务器端的功能框图。

图3用户终端会话实现的流程图。

图4设备终端会话实现的流程图。

图5设备终端数据转发用户终端流程图。

图6数据库数据存储实现流程图。

图7脑电波数据解析路程图。

图8socket通信超时处理流程图。

具体实施方式

下面结合附图对本发明做进一步描述。

参照图1~图8,一种基于twisted框架的脑电波数据传输的服务器,图1为基本的c/s(客户端/服务器)网络框架。利用基于tcp的socket方法,实现客户端和服务器通信。客户端分为设备端与用户端,设备客户端可以通过服务器将数据发送给用户客户端。

图2为设计的服务器的功能框图。简单来说,设计的服务器分为三个大部分:主模块、脑电波数据解析模块和数据库模块。其中,主模块为客户端会话实现部分,此部分包括设备和用户客户端与服务器会话实现模块以及用户设备关联模块。数据库模块通过与mysql数据库相连,可以实现数据库访问等操作。管理员需要事先将客户端的认证信息添加到数据库。

图3流程图表明服务器与用户终端实现会话的过程。具体过程如下:

1.1)服务器启动,调用函数listentcp监听端口,初始化userfactory()工厂,调用反应器方法reactor.run()进入监听循环。

1.2)userfactory()实例化userprotocol协议,准备处理用户终端的网络事件。

1.3)当有用户tcp连接请求时,触动connectionmade()事件,建立用户连接。刷新接入时间,建立心跳时间、为超时断开连接作准备。

1.4)成功建立连接后,接收的数据会触动事件datareceived(),接收到用户上发的数据。

1.5)分析用户上发的数据内容。如果用户还没有登录,则必须是登录命令,否则直接断开连接;如果是登录命令,且是第一次接入,调用getuserinfo()函数,查询数据库用户表,判断是否是合法,如果是则允许登录,否则直接断开连接;如果是登录命令但用户已经登录,查询这次命令的ip和端口,是否与上次成功登录的ip和端口相同,如果相同,在忽略本次命令,如果不同,则退出上次登录,再重新登录。是不是第一次接入。如果是第一次接入,调用getuserinfo()函数判断序列号是否合法。如果不是第一次接入,即首次接入显示标志位为false,则直接跳过验证过程,直接添加设备终端。

1.6)用户终端登录后,判断是否有新的用户终端接入,有回到步骤1.3),重新进行循环。同时,判断用户接入时间是否超过用户的设定时间timeout。

1.7)如果超过设定时间timeout,则触动connectionlost()事件,断开连接,删除用户,并清空缓存。清除缓存代表着一次用户会话的结束。

1.8)接收到的命令和参数是合法的,则直接执行;如果是非法的或者参数有误,则返回错误信息。如果是查询历史数据等需要花费很长时间的命令,则采用从twisted.internet.threads导入defertothread()函数,转换成线程在后台运行,避免userprotocol协议的阻塞。

设备会话实现如图4所示,具体步骤为下:

2.1)启动服务器。调用reactor.listentcp()函数,初始化工厂dev2factory,监听相应tcp端口,调用reactor.run(),进入监听循环,准备设备终端事件处理。

2.2)devfactory()实例化devprotocol,用于处理设备的通信事件。

2.3)设备终端接入时触动connectionmade()事件,建立设备连接。获取当前时刻,作tcp超时准备。

2.4)建立连接后,设备上报的数据触动datareceived()事件,接收数据并作数据处理。设备终端的数据处理包括数据解析、转发用户和存入数据库等操作。这里侧重点于介绍设备终端的会话实现。

2.5)触动datareceived()事件后,解析数据。

2.6)如果设备还没有登录,则从数据中提取出设备序列号,查询数据库进行验证。如果已经登录,则跳过认证。

2.7)判断数据库中序列号是否存在,存在则实例化序列号,设备姓名,设备id,调用adddevice()函数对设备终端进行登录。标志第一次接入的标志位,置为false,供后续登录跳过认证。不存在的序列号直接调用transport属性loseconnection()方法断开连接,删除不合法设备终端。

2.8)判断是否有新的设备终端接入,有则重新2.3)步骤,重新进行循环。同时服务器端判断是否接收到设备终端关闭socket的信息。

2.9)接收到关闭连接信息,则触动connectionlost()事件,此事件调用deldevice()函数删除登录设备。设备终端删除表示着一次终端会话的结束。

结合图5,设备数据发送用户终端过程为:

3.1)在2.4)中,设备终端建立连接后,触动datareceived()事件后,会将设备终端数据转发给用户终端。

3.2)首先判断接收到的数据是否为空,为空直接结束。有数据则调用接口函数getonlineuser()获取所有在线用户,为转发数据做准备。

3.3)判断获得的用户是否存在,不存在的用户直接结束。存在的用户继续下一步。

3.4)用户存在则将当前时间time()赋值于starttime,为转发耗时作准备。并遍历每一个在线用户,

3.5)遍历后每一个在线用户,利用transport属性的write方法将设备数据发送给每一个在线用户终端。

3.6)日志打印转发耗时时间。一次设备终端数据转发用户终端设备到此结束。

数据库管理包括管理员对数据库的添加和删除、验证和设备数据的存储。结合图6,说明设备数据在数据库中的存储过程,具体如下所示:

4.1)服务器运行后,调用数据库db模块中函数db_init_test()初始化数据库中的表和字段。

4.2)在2.4)中,终端接入后触动datareceive()事件,开始数据处理。

4.3)事件datareceived()触动后首先判断数据是否为空,为空直接结束。不为空的数据会进行后续处理。

4.4)非空数据调用接口函数prototrans.neurodata()进行解析,解析成功的数据保存在字典recorddict中。并进行数据库认证,合格的设备登录。

4.5)进一步判断解析出来的数据是否为空,不为空的解析数据调用函数addrecord()将设备数据添加到缓存recordbuff中。

4.6)在定时程序下,当满足一定条件后,会调用函数auth_dev_history()将缓存中的设备数据添加到数据库中,从而完成对设备历史数据的存储。至此,数据库中存储流程结束。

图7是脑电波数据解析流程图,具体解析过程如下:

5.1)在2.4)中,设备端触动datareceived()事件后,调用接口函数prototrans.neurodata()解析数据,解析正确数据最终会被存储到数据库中。

5.2)在模块prototrans中,首先调用parseneuropacket()函数对数据包进行预解析,并进行数据包头checksum校验。

5.3)校验正确的数据将继续调用函数parseneurolab()解析内容,并将数据输出。解析出来的数据存储在4.4)字典recorddict中,供后续使用。

图8说明是通信过程中出现的超时检错机制。当连接中无数据传输时候,超过一定时间就提供异常和错误报告。具体流程步骤如下:

6.1)终端接入时候,触动conectionmade()事件,刷新终端接入时间,为超时作准备。

6.2)触动datareceived()事件处理数据。判断处理一个终端的的时间与设定的超时时间作对比。

6.3)若处理终端的时间大于超时时间timeout,触动connetionlost事件,断开tcp连接。若没有超过定时超时时间则等到时间超过定时间,会断开连接。

本实施例预留了其他功能空间,具有良好的扩展性。比如会话实现,只需要在终端添加相应以及在服务端添加相应的处理方法,即可实现会话的扩展性,丰富会话的实现。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1