基于VC++的串口通信服务的开发

更新时间:2024-06-25 15:48:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

无线传感网络课程论文

无线传感网络实现

题 目学 院专业班级学生姓名指导教师

协议栈串口转无线通信的实现 通信与电子工程学院

通信104班

姜允鑫

苗凤娟

2013年 6 月 10 日

Uart2RF Zstack

无线传感网络课程论文

摘 要

随着计算机技术的发展和推广,利用串口进行数据通讯在通讯领域中占有着重要的地位。为了方便和快速的通过Internet网络访问串口服务器的串口,本课题把串口通信集成到Windows服务,由Windows服务完成串口通信的基本操作。文中详细描述了串口通信服务的原理和工作流程,还列举出了相关的核心代码。用流程图的方式来描述了各个模块的逻辑实现。串口通信服务中采用安全队列的机制来控制多线程访问多串口。在开发中按照软件工程的流程,从需求分析到概要设计,从详细设计到编码,以及最后的测试,利用软件工程的工具管理开发代码和文档。此外,还开发出了客户端来测试该服务工作是否正常。经过测试服务工作正常,能通过网络连接到服务器完成串口的通信。最后总结了开发和设计的不足之处,程序还有待进一步完善。

关键词:串口 通信

无线传感网络课程论文

Abstract

With the development and spread of computer technology, serial communication is an important part in the field of computer network communication. In order to access server's serial port more convenient and faster through the Internet, this topic put serial communication services integrated into Windows service, which completed the basic operation of serial communication services. The serial communications services and the workflow are in detail described. The core code of the services is also given. Flow chart is used to describe the handling process of the serial communications services. The services using safe queue mechanism to control multithreading visit serials. During the entire development, according to the software engineering flow, from requirements analysis to summary design, from detail design to coding, and the final test, uses the software engineering tools to management the code and documentation. In addition, I developed a client to test the service. Test results of the experiment indicate the services can work normally. In the end, summarizes the disadvantages of the design and development, and further perfection of studies is surely in need.

Key words: Serial Communication;

III

无线传感网络课程论文

目 录

摘 要 ............................................................................................................................. II Abstract ........................................................................................................................ III 目 录 ............................................................................................................................ IV 第一章 引言 .................................................................................................................. 1

1.1实验目的 ..................................................... 1 1.2实验原理 ..................................................... 1 1.3实验准备 ..................................................... 1 1.4实验内容 ..................................................... 1 1.5课题背景 ..................................................... 2 1.6研究现状 ..................................................... 2 1.7 研究的意义 ................................................... 2 第二章 相关理论基础 ............................................................................................................... 3

2.1 Windows NT 服务 .............................................. 3 2.2 串口通信 ..................................................... 3 2.3 多线程及线程间通信 ........................................... 4 2.4 安全队列 ..................................................... 5 2.5 Windows套接字规范 ........................................... 6 2.6 客户机服务器系统 ............................................. 7 第三章 需求分析及设计方案 .................................................................................................. 9

3.1功能需求 ..................................................... 9

3.1.1服务器端 ................................................ 9 3.1.2串口通信 ................................................ 9 3.1.3客户端 .................................................. 9 3.2 设计方案 ......................................................................................................................... 9

3.2.1 服务器端 ................................................ 9 3.2.2 串口通信 ............................................... 10 3.2.3客户端 ................................................. 10 3.2.4开发工具 ............................................... 10

第四章 具体设计流程与实现 ................................................................................................ 11

4.1安全队列 .................................................... 11 4.2服务应用程序 ................................................ 13 4.3 串口通信 .................................................... 19

无线传感网络课程论文

4.4 客户端 ...................................................... 21 4.5 类图 ........................................................ 22 第五章 调试与分析 ................................................. 25 结 论 ............................................................. 26 参考文献 ........................................................... 27

无线传感网络课程论文

第一章 引言

1.1实验目的

熟悉TI的ZStack协议栈ZStack-CC2530-2.5.1a,理解各层次功能以及使用方法。

1.2实验原理

基于标准官方发布的Zstack进行移植修改,以适应CW-ZB2530的硬件平台,使用其中的SampleApp进行修改,实现了Coordinator和Router板之间的无线通信,并进行串口互传实验。

1.3实验准备

用IAR Embedded Workbench for 8051 8.10打开Lab8-Uart2RF目录中的eww工程文件,连接好调试器和开发板,用串口数据线连接开发板的串口J9和电脑,打开串口终端软件,配置号串口,波特率115200,这里需要准备两套串口传输线,两个PC串口,两个串口终端软件。将模块上的BNC头CN1上的红色保护套摘下,旋上开发套件中的2.4GHz天线。

1.4实验内容

由于官方的ZStack-CC2530-2.5.1a所适用的硬件平台为TI的SmartRF05和CC2530EM模块。并非CW-ZB2530模块,因此如果使用官方的Stack,需要进行相应的修改移植工作才能正常运行。在Lab8中的软件已经完成了这些修改,可以直接使用。

PC机通过串口发送数据给协调器Coordinator(短地址为0000),Coordinator通过无线广播方式发送出去,路由器接收到后把数据通过串口传给PC的串口终端显示出来。反之亦然。

使用时下载协调器程序:选中CoordinatorEB

1

无线传感网络课程论文

1.5课题背景

计算机与外界的信息交换称为通信。基本的通信方式有并行通信和串行通信两种。串行通信是指一条信息额各位数据被逐位按顺序传送的通信方式。串行通信的特点是:数据位传送,按位顺序进行,最少只需要一根传输线即可完成,成本低但传送速度慢。串行通信的距离可以从几米到几千米。

1.6研究现状

串口通讯目前流行的方法大概有三种:一是利用Microsoft提供的CMSCOMM控件进行通讯,不过现在很多程序员都觉应该放弃这种方式。二是利用WINAPI函数进行编程,这种编程的难度高,要求掌握很多的API函数。三是利用现在网络上面提供的一些串口通讯控件进行编写。这三种方法都没有同Windows服务联系起来。

1.7 研究的意义

利用串口进行数据通讯在通讯领域中占有着重要的地位,串口通讯在通讯软件中有着十分广泛的应用。如电话、传真、视频和各种控制等。通过本文的研究和开发能更加方便的通过网络通信来实现串口通信,提高串口的利用率。为进一步的研究提供参考。

2

无线传感网络课程论文

第二章 相关理论基础

2.1 Windows NT 服务

有那么一类应用程序,是能够为各种用户(包括本地用户和远程用户)所用的,拥有用户授权级进行管理的能力,并且不论用户是否物理的与正在运行该应用程序的计算机相连都能正常执行,这就是所谓的服务了。每个操作系统都需要有在后台执行任务的方法,无论是谁正在使用这部机器,这些任务都可以继续运行,后台任务可以处理各种重要的服务,包括系统的或者用户的。

在Windows NT中,后台的任务被称为服务。服务可在每次NT启动的时候运行,并且不管是谁登陆,都会一直运行下去。服务是一类受到操作系统优待的程序。一个服务首先是一个Win32可执行程序,通常以控制台程序的形式被编写,进入点函数是Main()而不是WinMain()。

一个Windows NT服务由三部分组成,第一部分是Service Control Manager(SCM)。每个Windows NT/2000系统都有一个SCM,SCM存在于Service.exe中,在Windows启动的时候会自动运行,伴随着操作系统的启动和关闭而产生和终止。这个进程以系统特权运行,并且提供一个统一的、安全的手段去控制服务。它其实是一个RPC Server,因此我们可以远程安装和管理服务,不过这不在本文讨论的范围之内。SCM包含一个储存着已安装的服务和驱动程序的信息的数据库,通过SCM可以统一的、安全的管理这些信息,因此一个服务程序的安装过程就是将自身的信息写入这个数据库。第二部分就是服务本身。一个服务拥有能从SCM收到信号和命令所必需的特殊代码,并且能够在处理后将它的状态回传给SCM。第三部分也就是最后一部分,是一个服务控制管理器(Service Control Dispatcher,SCP)。它是一个拥有用户界面,允许用户开始、停止、暂停、继续,并且控制一个或多个安装在计算机上服务的Win32应用程序。SCP的作用是与SCM通讯,Windows 2000管理工具中的“服务”就是一个典型的SCP。

2.2 串口通信

串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是“数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准”该标准规定采用一个 25 脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的

3

无线传感网络课程论文

电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺。

典型地,串口用于ASCII码字符的传输。通信使用3根线完成:地线,发送线,接收线。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其它线则用于硬件握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配:

波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。

数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。

2.3 多线程及线程间通信

进程(Process)是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体。进程则不同,它是程序在某个数据集上的执行,是一个动态实体。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消,反映了一个程序在一定的数据集上运行的全部动态过程。

线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位。线程不

4

无线传感网络课程论文

能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。

线程带来的主要好处是:在进程内创建、终止线程比创建、终止进程要快;同一进程内线程间的切换要比进程间的切换要快,尤其是用户级线程间的切换。另外,线程的出现还因为以下几个原因:并发程序的并发执行,在多处理环境下更为有效。一个并发程序可以建立一个进程,而这个并发程序中的若干并发程序段就可以分别建立若干线程,使这些线程在不同的处理机上执行。每个进程具有独立的地址空间,而该进程内的所有线程共享该地址空间。这样可以解决父子进程模型中,子进程必须复制父进程地址空间的问题。线程对解决客户/服务器模型非常有效。

线程之间通信的两个基本问题是互斥和同步。线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。线程互斥是指对于共享的操作系统资源(指的是广义的“资源”,而不是Windows的.res文件,譬如全局变量就是一种共享资源),在各线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥是一种特殊的线程同步。实际上,互斥和同步对应着线程间通信发生的两种情况:当有多个线程访问共享资源而不使资源被破坏时;当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。在WIN32中,同步机制主要有以下几种:事件(Event);信号量(semaphore);互斥量(mutex);临界区(Critical section)。

2.4 安全队列

队列(Queue)在计算机科学中,是一种先进先出的线性表。和栈相反,它只允许在表的一端进行插入,而在表的另一端删除元素。队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端为队尾,进行删除操作的端为队头。队列中没有元素时,称为空队列。在用链式存储结构表示队列时,需要设置队列头指针和队列尾指针,以便指示队列头结点和队列尾结点。

安全队列是指高级队列的代理明确指出一个或多个数据库用户可以对队列进行操作。安全队列的拥有者可以执行所有的队列操作,而其他用户除非被配置

5

无线传感网络课程论文

为这个安全队列的安全队列用户,否则不能对这个安全队列执行操作。安全队列在队列的入队和出队操作时的各线程同步。在某一时刻只能有一个线程操作该队列,这样的队列就是安全的队列。把队列的队头视为临界区,要对队列进行操作需进入临界区,从而实现现成的同步,队列的安全。

2.5 Windows套接字规范

随着个人计算机的日益普及,Windows操作系统的用户与日俱增。Microsoft以Berkeley Socket规范为范例定义了一套Microsoft Windows下的网络编程接口,它不仅包含了人们很熟悉的Berkeley Socket风格的库函数,也包含了一组针对Windows的扩展库函数,一是程序员能充分利用Windows消息驱动机制进行编程。

Windows Socket规范本意在于提供给应用程序开发者一套简单的API,并让各家网络软件供应商共同遵守。此外,在一个特定版本Windows的基础上,Windows Socket规范也定义了一个二进制接口(ABI),并通过此二进制接口来保证其兼容性。因此这份规范定义了应用程序开发者能够使用,而且网络软件供应商也能够实现的一套函数调用和相关语义。

遵守这套Windows Socket规范的网络软件,称之为Windows Socket兼容,而Windows Socket兼容实现的提供者,称之为Windows Socket提供者。一个网络软件供应商必须百分之百地实现Windows Socket规范才能做到Windows Socket兼容。

Windows Socket规范定义并记录了如何使用API与Internet协议相连接,尤其要指出的是,所有的Windows Socket实现都支持流式套接字和数据报套接字。应用程序调用Windows套接字的API实现相互之间的通信。Windows套接字有利用下层的网络通信协议功能和操作系统调用实现实际的通信工作。

在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:非对等作用和异步通信。客户机/服务器模式在操作过程中采取的是主动请示方式。首先服务器方要先启动,并根据请示提供相应服务:打开一个通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求;等待客户请求到达该端口;接收到重复服务请求,处理该请求并发送应答信号;返回第二步,等待另一客户请求;关闭服务器。客户方:打开一个通信通道,并连接到服务器所在主机的特定端口;向服务器发送服务请求报文,等待并接收应答;继续提出请求;请求结束后关闭通信通道并终止。

Windows Socket 2.0是Windows Socket 1.1发展的一个比较重大的变革,为了能与Windows Socket 1.1实现很好的兼容性,它在这基础上做了向后兼容:

6

无线传感网络课程论文

源码和二进制代码。这就实现了Windows Socket应用程序和任何版本的Windows Socket实现之间的最大的互操作性,同时也减少了Windows Socket应用程序使用者、网络协议栈提供者和服务提供者的许多痛苦。

2.6 客户机服务器系统

客户机服务器系统(Client/Server System)是计算机网络(尤其是Internet)中最重要的应用技术之一,其系统结构是指把一个大型的计算机应用系统变为多个能互为独立的子系统,而服务器便是整个应用系统资源的存储与管理中心,多台客户机则各自处理相应的功能,共同实现完整的应用。用户使用应用程序时,首先启动客户机通过有关命令告知服务器进行连接以完成各种操作,而服务器则按照此请示提供相应的服务。这是网络软件运行的一种形式。通常,采用客户机/服务器结构的系统,有一台或多台服务器以及大量的客户机。服务器配备大容量存储器并安装数据库系统,用于数据的存放和数据检索;客户端则安装专用的软件,负责数据的输入、运算和输出。

客户机和服务器都是独立的计算机。当一台连入网络的计算机向其他计算机提供各种网络服务(如数据、文件的共享等)时,它就被叫做服务器。而那些用于访问服务器资料的计算机则被叫做客户机。严格说来,客户机/服务器模型并不是从物理分布的角度来定义,它所体现的是一种网络数据访问的实现方式。采用这种结构的系统目前应用非常广泛。如宾馆、酒店的客房登记、结算系统,超市的POS系统,银行、邮电的网络系统等。

计算机网络的主要用途之一是允许共享资源。这种共享是通过相呼应的两个独立程序来完成的。每个程序在相应的计算机上运行。一个程序在服务器中,提供特定资源;另一个程序在客户机中,它使客户机能够使用服务器上的资源。例如,你正在计算机上用一个文字处理程序(如Word)进行工作,你告诉程序,你要编辑一个存贮在网络的另一台计算机中的特定的文件。你的程序将给那台计算机发送一个信号,请求它把这个文件传输过来。在这种情况下,你的文字处理程序是客户机,此时接受这种请求并发出这个文件的程序叫服务器,更确切地说它是一个文件服务器。

这种系统的绝妙之处,就是客户机和服务器程序不在同一台计算机上运行,这些客户机和服务器程序通常归属不同的计算机。例如,你可能坐在中国北京的一台PC机前,通过WWW来阅读万里之外的美国国家安全局的“今日新闻”,看一看美国总统选举的闹剧。在这种情况下,WWW客户机就是你的PC机,它运行着一个程序,此时WWW服务器是在美国另一端的一台超级计算机,它运行着另一个程序。

大部分计算机网络(包括所有的Internet服务)都使用这种客户机/服务

7

无线传感网络课程论文

器关系。要懂得怎样使用计算机网络(尤其是Internet),事实上就意味着要懂得怎样使用每个客户机程序。你的任务是启动客户机,并叫它执行程序。客户机的任务是连接上相对应的服务器,并确保你的指令正确执行。

客户机服务器工作时通常由一个公共的规制需要遵守,通信双方需要共同遵守这个规则才能保证通信的有效性,如需要传输大量语音数据时,需采用一种无须建立连接的传输方式,在这种方式下,数据可以以较快的熟读传输,而当需要确保数据准确无误地到达时,则应采用另外一种面向连接的传输方式。

8

无线传感网络课程论文

第三章 需求分析及设计方案

3.1功能需求 3.1.1服务器端

串口服务器上的串口通信服务打开一个固定的端口,监听客户端的Socket连接。若检测到客户端的连接则为客户端分配一个串口,供客户端发送数据。客户端同服务器协商好串口的配置信息,则客户端发送的数据服务器直接发送到串口,通过串口发送除去。若服务器检测到串口接受到数据,者直接把接收到的数据发送到客户端。即服务器中转串口和客户端的数据。这样一来客户端就好像直接链接到串口服务器上的串口,与服务器串口相连接的外设进行通信。串口服务器具有很多个串口形成一个串口池。串口池中的串口连接着不通或相同的外设,客户通过Internet联网的方式链接到服务器,同服务器的外设通信。 3.1.2串口通信

串口通信服务管理整个串口池。服务程序对串口池进行合理管理和分配,服务器端接收到客户端的连接请求,服务器会从串口池中选取一个串口供客户端使用。当客户端通信完毕,断开同服务器的链接时,服务器端回收这个串口,以供其他客户端使用。在分配串口的时候不能让不同用户使用同一串口,让每一个客户端独立的使用某一个串口。当客户端链接上服务器后,服务器为客户端分配一个串口供客户端使用。这时候串口通信需要被实现。包括串口的打开,串口参数设置,读写数据到串口以及关闭串口。

3.1.3客户端

客户端的需求相对简单。连接服务器的客户端通过指定服务器地址和端口号连接到服务器,设置串口的通信参数,同服务器通信。可以发送数据到服务器和接受服务器发送回来的数据,并显示接收到的数据。通信完毕时断开通服务器的连接。

3.2 设计方案

3.2.1 服务器端

服务器端使用Windows NT服务来提供服务,此服务监听某一端口,等待客户端的链接。为客户端提供服务。使用Windows API自己定义服务的行为。服务管理串口池,服务启动初始化时,检测服务器的串口,串口统一进入一个全局安全队列。当客户端发起连接请求时,服务器开启一个线程来处理该客户的请求,直到客户端断开连接,线程退出执行。在线程中,从安全队列的队头出队列一个

9

无线传感网络课程论文

串口,该串口分配给该客户使用,客户端首先设置该串口的通信参数,否则按照默认串口通信参数进行通信。如果有多个客户同时连接服务器则服务器同时开启多个线程来处理多个用户的连接请求。分配给客户端使用的串口接收外设发来数据时,服务器通过连接的Socket发送到客户端,客户端处理接收到的数据。服务器端接收到客户端发来的数据时,把接收到的数据发送到分配给这个客户端的串口,通过串口发送到外设,外设处理接收到的数据从而做出反应,完成通信。 3.2.2 串口通信

使用Windows API的串口操作函数,封装成串口类,来处理串口通信。此串口类统一操作串口池里的串口,根据不同的串口号来操作这些串口。从而达到每一个客户的使用一个串口,每个串口都是相同的操作。可以根据不同的通信设备为不同的串口设置不同的通信参数。串口通信负责处理串口的参数设置,串口的打开和关闭,数据的读和写,即写数据到串口和从串口读数据。打开串口时,服务处理此客户的线程开启另一线程监听串口是否有数据接收,当发现有数据来的时候,串口读出该数据通过Socket发送到客户端。

3.2.3客户端

客户端使用MFC编程创建基于对话框的应用程序。该程序使用Windows Socket建立同指定服务器的数据连接。当建立好HTTP链接后,可设置串口的通信参数,如:波特率,数据位,奇偶校验,停止位等。设置好串口的通信参数后就可以同服务器分配给的串口链接的外设通信了。发送数据到服务器的串口,和接收服务器发送回来的数据。

3.2.4开发工具

Microsoft Visual C++ 6.0是微软公司推出的开发Win32应用程序(Windows 95/98/2000/XP/NT)的、面向对象的可视化集成工具。它的最大优点就是提供了功能强大的MFC类库,MFC是一个很大的C++类层次结构,其中封装了大量的类及其函数,很多Windows程序所共有的标准内容可以由MFC的类来提供,MFC类为这些内容提供了用户接口的标准实现方法,程序员所要做的就是通过预定义的接口把具体应用程序特有的东西填入这个轮廓,这将简化编程工作,大大的减少程序员编写的代码数量,使编程工作变得更加轻松容易。

10

无线传感网络课程论文

第四章 具体设计流程与实现

4.1安全队列

数据保护是在使用多线程技术时必须要解决的关键问题,防止多个线程同时操作某一变量,导致逻辑错误,是多线程协调运行的重要内容。线程安全队列这种数据保护机可以保护共享数据,实现线程间安全的数据传输。

一般地,每个进程中的线程都不知道进程中的其他线程的任何情况,除非我们在程序中明确的使他们互相可见。为了在不同时刻访问共享的资源,任何共享这些资源的线程都必须通过进程通信的手段进行调度。线程调度是一个复杂的问题,不正确的调度将导致进程的死锁。为了这种情况的发生,访问共享资源的线程必须进行同步。

临界区对象只有由同一个进程的线程共享,临界区对象在某一个时刻只能由一个线程所拥有。临界区对象不保证线程对临界区的访问顺序。进程负责分配临界区所使用的内存,一般声明一个类型为CRITICAL_SECTION的变量来完成此任务。在进程的线程使用临界区之前,必须使用函数InitializeCriticalSection或InitializeCriticalSectionAndSpinCount初始化临界区。线程使用函数EnterCriticalSection或函数TryEnterCriticalSection请求对临界区的拥有权。如果临界区对象正由其他线程所拥有,则函数EnterCriticalSection无限等待该拥有权。线程使用LeaveCriticalSection释放对临界区的拥有权。进程的所有线程都可以使用函数DeleteCriticalSection释放临界区对象初始化时分配的系统资源。

线程安全队列工作机制如图,操作队列的时候需要先进入临界区,操作完成后离开临界区,由此保证在任何时候都只有一个线程操作该队列。线程间的数据传输是安全可靠的。

11

无线传感网络课程论文

InitializeCriticalSectionEnterCriticalSection队列操作 入队列出队列LeaveCriticalSectionDeleteCriticalSection 图 1 安全队列工作机制

入队列相关代码:

BOOL Push(const Type & item) {

EnterCriticalSection(&lock); //进入临界区

_safe_queue_item *next=new _safe_queue_item (item);

if (first==NULL) last=first=next; else {

last->next=next; last=next; }

LeaveCriticalSection(&lock); //离开临界区 return TRUE; };

出队列相关代码:

Pop() {

EnterCriticalSection(&lock); //进入临界区 Type val;

_safe_queue_item *oldFirst=first; if(first==NULL) {

LeaveCriticalSection(&lock); throw \ } else {

val=first->value; first=first->next; delete oldFirst;

LeaveCriticalSection(&lock); //离开临界区

12

无线传感网络课程论文

}

4.2服务应用程序

在基于NT的系统中,全部服务任务都是由服务控制管理器(SCM)系统管理。SCM维持注册表中已知服务列表,打开各项服务(即可以是开机时自动打开,也可以使用户请求打开)。SCM把服务列表和它们的打开状态保存在注册表中,新服务项在安装时加入此列表中。另外也可以删除服务项目。作为服务任务的程序是一个普通的exe文件,但是必须满足特定的要求才能确切地与SCM连接。微软已经详细编制了这些函数的程序流,必须紧密依据此流程表,否则服务项目就不能运行。要求如下:

商业源代码,全套计算机毕业设计免费下载 http://www.ibaidusoft.com 更多全套设计联系QQ:1042897696

最新设计大全 http://www.bylw168.com/sf/20100915/3539.html 1.服务项目的EXE文件必须有一个普通的Main或WinMain函数,此函数必须立即(特定情况下是在30秒之内)调用函数StartServiceCrtlDispatcher。调用之后,EXE文件就在SCM中注册,并且给出一个调用函数ServiceMain(在启动服务时调用)的指针。可以更改函数ServiceMain的函数名,然后就能在ServiceMain下面的记录文本中找到所用函数名的描述。main函数应该在注册ServiceMain之后返回。不能用命令行方式运行服务的exe文件。而应该在SCM知道的服务列表中安装,SCM会调用main函数,打开EXE文件。偶然用命令行方式执行服务时一定会出错,因为它不能连接SCM。

2.SCM在打开服务时将调用函数ServiceMain。例如,当管理员选择“控制面板”上“服务”的start按钮时,SCM将在一个工作线程中执行函数ServiceMain。函数ServiceMain完成多项工作。其中最为主要的是立即调用函数RegisterServiceCtrlHandler,该函数能用SCM注册一个函数Handler以调用控制要求。此函数的函数名可以随便更改,但大会在Handler下面的记录文本中列出。函数RegisterServiceCtrlHandler返回一个句柄,服务在给SCM发送状态信息时将用到该句柄。函数ServiceMain还开始将完成实际服务任务的工作现程。一旦线程开始,函数ServiceMain就等待一个事件的发生。直道服务停止,函数ServiceMain才返回。之后,重新调用函数ServiceMain,SCM将重新开始该项服务。

3.函数Handler包含一个转换语句,用于分析来自SCM的控制请求。默认时,SCM发送以下控制常数:

SERVICE_CONTROL_STOP 通知服务停止 SERVICE_CONTROL_PAUSE 通知服务暂停

13

无线传感网络课程论文

SERVICE_CONTROL_CONTINUE 通知服务重新开始

SERVICE_CONTROL_INTERROGATE 通知服务立即报告当前状态 SERVICE_CONTROL_SHUTDOWN 通知服务紧急关闭

用户也可以创建自定义常数(128~255之间),通过SCM把它们发送到服务项。当创建一个包含上述main、ServiceMain和Handler等函数的EXE文件以及一个包含服务线程的函数时,就得到了一个完整的服务任务。

服务的EXE文件ServeiceThread由函数ServerMain打开,该线程执行服务的具体任务对应暂停。继续停止等请求调用函数HandleHandle:Handle函数接收来自SCM的请求服务控制管理器SCM调用函数ServiceMain开始服务任务ServerMain:开始函数ServiceThread 告诉SCM关于函数Handle的信息在开机或安装后调用Main函数Main:Main函数告诉SCM关于函数ServerMain信息 图 2 服务中各部分之间的关系

Main函数,这是代码的入口。是在这里解析任何命令行参数并进行服务的安装,移除,启动等。提供真正服务代码的入口函数叫 ServiceMain。在服务第一次启动的时候,将该函数的地址传递给服务管理器。处理来自服务管理器命令消息的函数。这个函数叫 Handler,

服务回调函数,因为 ServiceMain 和 Handler 函数都是由系统来调用,所以它们必须遵循操作系统的参数传递规范和调用规范。也就是说,它们不能简单地作为某个 C++ 类的成员函数。这样就给封装带来一些不便,因为想把 Win32 服务的功能封装在一个 C++ 类中。为了解决这个问题,将 ServiceMain 和 Handler 函数创建成 CNTService 类的静态成员。这样就使得以创建可以由操作系统调用的函数。 但是,这样做还没有完全解决问题,因为系统不允许给被调用的函数传递任何形式的用户数据,所以我们无法确定对 C++ 对象特定实例的 ServiceMain 或 Handler 的调用。在这里用了一个非常简单但有局限的方法来解决这个问题。创建一个包含 C++ 对象指针的静态变量。这个变量是在该对象首次创建是进行初始化的。这样便限制每个服务应用只有一个C++对象。下面是

14

无线传感网络课程论文

NTService.h 文件中的声明:

class CNTService {

[...] // 静态数据

static CNTService* m_pThis; // nasty hack to get object ptr [...] };

下面是初始化 m_pThis 指针:

CNTService::CNTService(const char* szServiceName) {

m_pThis = this; [...] }

ServiceMain函数:

ServiceMain函数提供真正服务代码的入口。它完成多项工作。其中最为主要的是立即调用函数RegisterServiceCtrlHandler。之后ServiceMain做一些服务初始化的工作,为工作线程的运行提供必要的准备。最后函数ServiceMain还开始将完成实际服务任务的工作线程。一旦线程开始,函数ServiceMain就等待一个事件的发生。直到服务停止,函数ServiceMain才返回。之后重新调用函数ServiceMain,SCM将重新开始该项服务。流程如图:

RegisterServiceCtrlHandler初始化工作开始完成实际服务任务的工作线程 图 3 ServerMain函数流程

初始化工作OnInit函数:

OnInit函数的主要任务是初始化全局变量串口队列。扫描服务器的串口,如果串口可用,则把此串口进入安全队列。以备客户端请求使用。

15

无线传感网络课程论文

初始化还有串口是该串口是否可用否下一串口是入队列否结束 图 4初始化工作流程

相关代码:

for(i=1;i<=ComCount;i++) { }

sprintf(buf,\

if (com.EPortAvailable==com.CheckPort(buf))

ComQueue.Push(i); //串口入队列

服务工作线程ServiceThread由Run函数实现:

ServiceThread由函数ServerMain打开,开始完成实际服务任务的工作线程,该线程执行服务的具体任务。该函数绑定服务器地址后监听本地端口等待客户端的连接,当客户端连接上后,创建子线程,由子线程来处理这个连接,函数继续监听本地端口。子线程处理完链接后关闭链接套接字退出。

图 5 服务工作线程流程

相关代码:

sockaddr_in service;

16

无线传感网络课程论文

service.sin_family=AF_INET;

service.sin_addr.s_addr=INADDR_ANY; //ip地址 service.sin_port=htons(2501); //端口号

bind(m_socket,(SOCKADDR*)&service,sizeof(service)); listen(m_socket,20); //监听连接

while (m_bIsRunning) { //直到服务停止运行

AcceptSocket=SOCKET_ERROR; while(AcceptSocket==SOCKET_ERROR) { }

AcceptSocket=accept(m_socket,NULL,NULL);//接收连接

//创建子线程处理该连接

CreateThread(NULL,NULL,AnswerThread,(LPVOID)AcceptSocket,0,&TId); }

服务子线程:

由类的静态成员函数作为线程函数。在线程中,首先判断服务器是否还有剩余串口可分配,也就是判断串口队列中是否为空。若为空,则提示用户服务器串口已使用完毕,请稍后在试,断开同客户端的连接。否则串口队列出队列一个串口,分配给该客户使用,接下来就是打开串口,配置串口参数,开启串口监听线程,等待客户端发送的数据。直到客户端断开连接,串口重新进入队列,等待下次的分配。服务子线程退出。

串口队列为空是提示信息开启监听线程否串口出队列打开串口配置串口参数退出串口入队列关闭串口是链接断开否接收客户端发送数局从串口发送除去

图 6 服务子线程工作流程

相关代码:

17

无线传感网络课程论文

{ }

if(!ComQueue.IsEmpty()) //判断队列是否为空 { } Else

//发送提示信息到客户端

send(ClientSocket,szBuffer,strlen(szBuffer),0); closesocket(ClientSocket);//断开连接

com=ComQueue.Pop(); //出队列 sprintf(buf,\//打开串口配置默认通信参数

Serial.Open(buf,ClientSocket,1024,1024); Serial.StartListener(); //开启监听线程 while(bytesRecv) //连接是否断开 { }

Serial.StopListener(); //停止监听子线程 Serial.Close(); //关闭串口 ComQueue.Push(com); //串口入队列

while(bytesRecv==SOCKET_ERROR) {

//接受客户端的数据

bytesRecv=recv(ClientSocket,recvbuf,1024,0); }

Serial.Write(recvbuf,&Len); //写串口

服务的安装

要使用服务,首先应进行安装。安装过程使SCM知道有这项服务存在,让SCM把它添加到服务列表中。通过调用函数OpenSCManager,打开一个到服务控制管理器的连接。然后调用函数CreateService在SCM数据库中安装服务。函数CreateService的调用中使用了打开SCM的指针,服务名,识别符以及一族填充其他值的基本参数。服务名是指在scm内部使用的服务的名字,删除服务时指定改名字可删除该服务,识别符是指在“控制面板”的“服务”中表示服务项的识别符。最后关闭服务控制管理器的连接。

18

无线传感网络课程论文

打开SCM的连接CreateService创建服务关闭SCM的连接 图 7 服务安装流程

服务的卸载

卸载服务时,同样需要先打开一个到服务控制管理器的连接。然后查询该服务当前是否是被停止,若还未停止,则调用函数ControlService尝试停止该服务。这样做有利于卸载服务项:如果服务在删除过程中继续运行,则“控制面板”中”服务“将保留与服务的连接,实际上服务可以继续运行;当有人试图停止该“孤儿”服务时,“服务”可能就会抗议。先停止服务再删除它,就可以避免该问题。服务停止后,调用函数DeleteService删除该服务。

打开SCM连接服务是否停止是否删除服务关闭服务 图 8 服务卸载流程

4.3 串口通信

串行口在Win 32中是作为文件来进行处理的,而不是直接对端口进行操作。在Win32环境下,可以把串口看作由文件系统访问的设备。使用标准的CreateFile()函数打开端口,再使用ReadFile()和WriteFile()函数读写数据,就如同端口只是一个文件对象一样。对于串行通信,Win 32提供了相应的文件I/O函数与通信函数,使用这些函数,可以编制出符合不同需要的通信程序。

通常实现串行通信的步骤如下:

1.按协议的设置初始化并打开串行口,这样做就是通知Windows本应用程序需要这个串口,并封锁其他应用程序使它们不能使用此串口。

2.配置这个串行口。

3.在串口上往返地传输数据,并在传输过程中进行校验

4.不需要此串口时,关闭串口,即释放串口以供其它应用程序使用。 在这四个步骤中,主要的程序代码集中在第3步。

打开串口配置串口传输数据关闭串口

图 9 串口通信流程

19

无线传感网络课程论文

串口通信直接使用Windows API函数封装成类。应用API函数进行串口编程时,步骤如下:

1.打开串口:CreateFile函数。

2.建立串口通信事件:CreateEvent函数。

3.初始化串口,设置串口参数:SetCommState函数。

4.建立读数据的线程:建立线程简单程序中并非需要,需要用到的函数较多,如ReadFile。

5.写数据:用WriteFile函数。

6.结束时关闭串口:若程序中打开了其他线程,则先终止线程。停止WaiteCommEvent的等待以及关闭串口CloseHandle,平时程序会停留在WaiteCommEvent的等待中,当要终止线程的时候,程序必须 从WaitCommEvent中退出来,然后用CloseHandle关闭串口。

相关代码如下: 串口的打开:

// Open COM port

m_hFile = ::CreateFile(lpszDevice,

GENERIC_READ|GENERIC_WRITE, 0, 0,

OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

串口的关闭: // Close COM port ::CloseHandle(m_hFile);

GetCommState(m_hFile,&dcb);//获得串口当前参数 dcb.BaudRate = DWORD(eBaudrate); //重新配置串口参数 dcb.ByteSize = BYTE(eDataBits); dcb.Parity = BYTE(eParity); dcb.StopBits = BYTE(eStopBits); dcb.fParity = (eParity != EParNone);

SetCommState(m_hFile,&dcb);//设置新的串口参数

设置串口参数:

读写串口:

20

无线传感网络课程论文

::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped);//读串口 ::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped);//写串口

4.4 客户端

相对于服务器,客户端的设计和实现比较简单。客户端只需要建立同服务器的Socket连接,发送数据,接受服务器发送来的数据即可。其流程如图:

初始化建立连接接收和发送数据断开连接 图 10 客户端处理流程

相关代码:

[...] 初始化

m_ClientSocket.Create(); //创建套接字

m_ClientSocket.Connect(buf,m_ServerPort);//建立连接 m_ClientSocket.Send(m_Send,m_Send.GetLength());//发送数据 //接收数据

m_ClientSocket.Receive(GetBuffer(1024),m_Receive.GetLength(); m_ClientSocket.Close(); //断开连接

21

无线传感网络课程论文

4.5 类图

CNTService-m_bIsRunning : bool = false-m_hEventSource-m_iMajorVersion-m_iMinorVersion-m_pThis-m_szServiceName-m_AcceptSocket+Handler()+Inialize()+Install()+IsInstalled()+OnContinue()+OnInit()+OnInterrogate()+OnPause()+OnShutdown()+OnStop()+ParseStandardArgs()+Run()+ServiceMain()+StratService()+Uninstall()+AnswerThread()CSerial-m_dwEventMask-m_eEvent-m_fStopping : bool = true-m_hevtOverlapped-m_hFile-m_hThread-m_lLastError-m_Socket+CheckPort()+Close()+GetEventMask()+GetEventType()+Open()+Read()+SetMask()+Setup()+StartListener()+ThreadProc()+WaitEvent()+Write()SafeQueue-first-last-lock+IsEmpty()+Pop()+Push()+Reset()

图 11 类图

CNTService:Windows NT服务类,实现了Windows NT的服务。 CSerial:串口类,实现串口通信。

SafeQueue:安全队列类,实现多线程安全访问队列。

4.6 附件

#if defined (ZTOOL_P1) || defined (ZTOOL_P2) uartConfig.callBackFunc = rxCB; ? 声明一个事件(SampleApp.h)

#define UART_RX_CB_EVT 0x0002 ? uart回调函数(MT_UART.c):

static void rxCB( uint8 port, uint8 event ) {

extern uint8 SampleApp_TaskID;

22

无线传感网络课程论文

rxlen=Hal_UART_RxBufLen(SERIAL_APP_PORT); //接收缓冲区数据长度 rbuf=osal_mem_alloc(rxlen+1); //分配缓冲区,多分配一个字节 rbuf[0]=rxlen; //第一个字节存放数据长度

HalUARTRead ( SERIAL_APP_PORT, rbuf+1, rxlen); //读接收缓冲区数据到rbuf if(!rxlen)

osal_mem_free( rbuf ); //释放内存 else

osal_set_event(SampleApp_TaskID,UART_RX_CB_EVT); //触发事件 }

说明:如果uart的buffer中有数据就会调用这个函数,这个函数的功能是利用Hal_UART_RxBufLen读取buffer中数据的长度,并将其放在rbuf[0]中。利用HalUARTRead读取buffer的数据放在buffer的其他位置。最后触发了UART_RX_CB_EVT事件。

? UART_RX_CB_EVT事件的处理(SampleApp.c)

if ( events & UART_RX_CB_EVT ) //串口有数据需要处理 {

SampleApp_SPI_SendData( rbuf, rxlen+1 ); //调用处理函数,将信息发送出去

return (events ^ UART_RX_CB_EVT); }

? SampleApp_SPI_SendData( rbuf, rxlen+1 )函数说明(SampleApp.c):

void SampleApp_SPI_SendData( uint8 *buf, uint8 len )

23

无线传感网络课程论文

{

SampleApp_SPI_SendData_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast; SampleApp_SPI_SendData_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_SPI_SendData_DstAddr.addr.shortAddr = 0xFFFF; if ( AF_DataRequest ( &SampleApp_SPI_SendData_DstAddr, (endPointDesc_t *)&SampleApp_epDesc, SAMPLEAPP_FLASH_CLUSTERID, len, buf,

&SampleApp_TransID, 0,

AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) {

osal_mem_free( rbuf ); //必须释放内存,不然造成溢出! } else {

osal_mem_free( rbuf ); //必须释放内存,不然造成溢出! } }

至此完成了数据从buffer中向空中发送的过程 下面是接受部分代码:

? 事件处理函数SampleApp_ProcessEvent(SampleApp.c):

if ( events & SYS_EVENT_MSG )//判断任务(一个任务可以有多个事件) {

while ( MSGpkt )//对比事件 { ??

case AF_INCOMING_MSG_CMD:

SampleApp_MessageMSGCB( MSGpkt ); break;

? SampleApp_MessageMSGCB( )函数说明(SampleApp.c):

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) {

switch ( pkt->clusterId ) { ??

case SAMPLEAPP_FLASH_CLUSTERID://此clusterid由SampleApp_SPI_SendData函数发送数据

pointer1=&pkt->cmd.Data[1]; //接收数据指针,指向数据

HalUARTWrite(0,pointer1,pkt->cmd.Data[0]);//pkt->cmd.Data[0]是数据的大小 break;

24

无线传感网络课程论文

}

第五章 调试与分析

由于服务必须从服务控制管理器的上下文中运行,而不是从Visual Studio中运行,因此调试服务不像调试其他Visual Studio应用程序类型那样简单。若要调试服务,必须首先启动服务,然后将一个调试器附加到正在运行服务的进程中。然后可以使用 Visual Studio 的所有标准调试功能来调试应用程序。

附加到服务的进程能够调试大多数服务代码,但并非全部;例如,由于服务已经启动,因此不能用这种方法调试服务的 OnStart 方法中的代码,或调试用于加载服务的 Main 方法中的代码。

由于服务应用程序调试的特殊性,直接把服务应用程序里面的实际工作代码提取出来做成一般的应用程序,而后调试。这样更简单,直接。把调试好了的应用程序里面的代码放在服务里面就可以了。还有一种方法就是写日志文件。这也是调试服务的一个比较好的方法,虽然比较笨,但是通过阅读自己留下的日志,也能起到不小的作用的

25

无线传感网络课程论文

结 论

经过这几个月的时间,完成了基于VC++的串口通信服务的开发,是基于Windows Socket通信的客户端服务器系统。论文描述了系统的基本理论和实现方法。程序开发主要是实现Windows服务、串口通信、串口池的管理和客户端。由于是第一次接触到这方面知识,也存在很多不足之处。系统功能还没有那么完善,在通信基础上还可以加上具体的协议来实现真正意义上的数据通信。这些都是有待进一步开发的后续工作。

我尽量使此次分析和设计符合科学性、实际操作性的原则。但由于个人水平限制原因,我对这个课题研究还不是很深入,论文本身还存在诸多欠妥之处,恳请老师与同学们给我提出宝贵的意见,我将在以后的研究中进一步完善和深化。总而言之,要不断加强学习,时刻关注技术的发展。在理论知识的指导下,将新的、先进的技术引入到系统中,并在这个领域中不断学习研究。

26

无线传感网络课程论文

参考文献

[1] 乔林,杨志刚.Visual C++ 6.0高级编程技术——MFC与多线程篇[M].北京:中国铁道出

版社,2000。

[2] 雷斌,杨建华,黄超,何斌.Visual C++ 6.0网络编程技术[M].北京:人民邮电出版

社,2000。

[3] 汪翔,袁辉.Visual C++实践与提高——网络编程篇[M].北京:中国铁道出版社,2001。 [4] 龚建伟,熊光明.Visual C++/Turbo C串口通信编程实践[M].北京:电子工业出版社,

2004。

[5] 谭思亮,邹超群.Visual C++串口通信工程开发实例导航[M].北京:人民邮电出版

社,2003。

[6] 郭晓鹏,李存斌.Visual C++高级编程及其项目应用开发[M].北京:中国水利水电出版

社,2004。

[7] 王险峰,刘宝宏.Windows环境下的多线程编程原理与应用[M].北京:清华大学出版

社,2002。

[8] 张锦,张俊.深入学习:Win32系统服务开发与实例[M].北京:电子工业出版社,2001。 [9] 李凌.Winsock 2网络编程实用教程[M].北京:清华大学出版社,2003。

27

本文来源:https://www.bwwdw.com/article/wdo3.html

Top