新稿件基于VC的Modbus/TCP协议模型通信测试软件的实现郝晓弘,祖守圆,徐维涛(兰州理工大学电气工程与信息工程学院,甘肃兰州730050)摘要:Modbus/TCP协议是Modbus协议族在工业以太网上的解决方案。Modbus/TCP协议具有侦错能力强、数据传输量大、实时性好、开放性好等特点。所以得到广泛的采用。文章依据Modbus/TCP协议的要求,利用winsock和多线程机制实现该协议的通讯测试软件。关键词:Modbus/TCP;winsock;多线程;客户/服务器1.引言近年来,现场总线技术和工业以太网的快速发展,以及关键支持的突破,使得工业自动化领域控制级以上的通信网络正在逐步统一到工业以太网。同时,由于一些通信接口芯片的研制成功以及价格上的优势,导致了工业以太网技术的快速发展。目前工业以太网有四个主要的竞争者:Modbus/TCP工业以太网、Ethernet/IP工业以太网、FoundationFieldbusHSE工业以太网和Profinet工业以太网。其中,Modbus/TCP工业以太网较为流行、简单,是一种高效的控制方案解决标准,有成为主流的趋势。Modbus/TCP通信协议是一种被不同的现场总线厂家及协会广泛采用的工业以太网标准,对于现场总线控制中采用的TCP/IP协议通信的设备都适用,尤其适用于工业以太网中的I/O模块、PLC等设备与其他网络结点的数据交互。(如图1)Modbus/TCP协议是由Schneider公司发布的,是将Modbus总线协议与以太网TCP/IP协议结合形成的。它保留了Modbus协议原有的命令/应答方式、RTU和ASCII两种数据格式等特点;同时支持采用HTTP和XML在内的开放的Internet协议,使得Modbus/TCP除了作为现场总线使用外,还可在设备中内置网页服务器。从而使工业以太网上的I/O设备能够支持网上浏览I/O状态、系统工况,以及网络信息的繁忙度;也可为特殊节点定义相应的网页反映生产信息、故障诊断、报警记录以及发送E-mail信息给维护人员等。已有实验表明,基于Modbus/TCP协议的工业以太网控制系统,既可以用作控制,又可传输文件,并且其性能稳定性和传输速率也优于原由的各种现场总线控制系统。图1利用Modbus/TCP连入以太网的控制结构使用Modbus/TCP协议的工业以太网控制系统,利用VisualC++或其他商用软件开发工具,即可为系统建立网址、网页、可供多用户同时访问同一网址对应的现场设备。从发展的角度看,Modbus/TCP协议具有开放性,且易于理解和实现,必将被应用在越来越多的工业控制领域。2.Modbus/TCP协议1.1Modbus协议在网络协议栈中的意义Modbus与TCP/IP结合成为Modbus/TCP,它以一种非常简单的方式将Modbus帧嵌入到TCP帧中,使其成为工业以太网应用层协议。Modbus协议层在TCP之上,其主要完成的任务为:在服务器端,负责解译来自客户端的Modbus帧,执行相应的请求。在客户端,负责把来自用户的message(包含用户请求执行的操作和要控制的对象等信息)封装为Modbus帧。图2Modbus/TCP帧格式2.2Modbus/TCP的帧格式如图2所示,整个Modbus帧的大小不能超过256字节。其包括三个部分:(1)MBAPHeader(Modbus应用协议报头,共占用7字节)其分为四个部分:Transactionidentifier,占用2个字节,用来标识Modbus帧的次序,每多发送一个Modbus帧,该值加1;ProtocolIndentifier,占用2个字节,用来确定应用层协议是不是Modbus协议;Length,占用2个字节,给出UnitIdentifier子域和Data域的共同长度;UnitIdentifier,占用1个字节,它用来标识Modbus串行线上的某个设备单元。(2)Functioncode(功能码,占用1字节)分为位操作和16位字操作两大类。其中位操作主要用于像PLC这类设备。功能码指出要求进行的操作,比如功能码04代表输入寄存器,再如功能码06写单个16位字寄存器。(3)Data(数据域,占用字节的上限为148)其具体格式与功能码密切相关,它是一个可变长字段。总的说来,客户端发送请求数据时,数据域给出要操作的寄存器的起始地址和个数。而服务器端发送应答数据时,数据域给出被操作的寄存器个数以及n个寄存器的状态值。3.运用Winsock套接字来实现Modbus/TCP的通讯由于Modbus/TCP协议采用客户/服务器的通讯模型,实现比较复杂,所以可以利用VisualC++及其类库MFC来开发。在VisualC++中包含了开发网络应用程序两个基本的Winsock类:CAsyncSocket类和CSocket类。由于CAsyncSocket类只是对Winsock进行简单的封装,而CSocket类可以同SocketFile类进行连接操作。在实现中应用CSocket来实现Modbus/TCP的通信。首先在MFC的向导中选中WindowSockets项,在系统建立的框价中的StdAfx.h中加入#includeafxsock.h将MFCWinsock扩展文件加入进来,同时在InitInstance()中进行初始化系统,为连接Winsock做准备:if(!AfxSocketInit()){AfxMessageBox(IDP_SOCKETS_INIT_FAILED);returnFALSE;}在本测试中将客户/服务器端做到同一个工程项目中。所以在项目中建立了基于CSocket的CClientsocket类,并将该类的头文件加入到服务器的文件中。在设计服务器时,应让等待的线程在Modbus协议注册的TCP-502端口号来监听来自客户端的Modbus/TCP连接请求。整个系统采用面向连接的编程模型(如图3)图3面向连接编程模型1)服务器端程序设计在VC中,编写了服务器代码,其中和多线程相关的部分关键代码如下:voidCModbusDlg::OnClick()//使等待线程进入监听请求的状态{CClientsocketm_ClientSocket;//处于监听状态的套接字…………………………………………………………………………bind(m_ClientSocket,sockadd,len);//主线程在端口502侦听listen(m_ClientSocket,5);//while(m_connect)//m_connect变量决定是否允许主线程继续处理来自客户端的连接请求{SOCKETc=accept(m_ClientSocket,sockadd,len);AfxBeginThread(ClientThreadPorc,(LPVOID)c,THREAD_PRIORITY_ABOVE_NORMAL);//创建新线程WaitForSingleObject(m_hEvent,INFINITE);//等待新线程保存套接字句柄}closesocket(m_ClientSocket);}//新线程的代码UINTClientThreadProc(LPVOIDlpParam){SOCKETm_socket=(SOCKET)lpParam;SetEvent(m_hEvent);//使等候线程能被调用执行intkk=1;BYTE*curRecord,waitRecord;BYTE*curK=recvbuf=(BYTE*)malloc(4096);While(1)//无限循环,用来处理和这个线程建立连接关系的客户来的Modbus帧{kk=recv(m_sock,curK,256,0);curK+=kk;if(kk==0)//客户端关闭TCP连接{Closesocket(m_socket);return0;}}………………………………………处理Modbus帧数据代码}在其中很关键的是,创建新线程后,等待线程和线程被调度运行的先后顺序是确定的,如果等待线程先运行,又分配了一个新套接字,那么c变量的值将发生改变。此后等待线程又创建一个新的线程,这样就出现一个错误,同时有两个新线程使用同一个套接字。为了保证新套接字的句柄值被赋给唯一的线程,必须采用线程同步机制,在等待线程能处理下一个连接请求之前,它要等待一个事件,即WaitForSingleObject(m_hEvent,INFINITE)。m_hEvent是通过函数CreateEvent创建的全局变量。同时在新线程成功保存了新的套接字的句柄值后,通过SetEvent(m_hEvent)使得主线程能够被重新调度执行。2)客户端程序设计为了看的更清楚在这个程序中将客户端和服务器端的完成在同一个工程中,具体实现以处理流程图来实现。(如图4)在程序界面中可以清楚的看到服务器端传送数据和客户端可以对传来的数据进行删除和修改。(如图5)在客户端程序代码中先定义变量:CStringm_port=502;//端口号CStringm_IP=_T(“”);//服务器IP地址CStringm_con=_T(“”);//显示状态变量CListBoxm_list1;//读进的数据列表变量图4客户端流程图//连接操作函数在进行读取的消息中:voidCModubusDlg::OnRead(){……………………………//对服务器端的Modbus数据进行读取}//对采入的数据进行删除voidCModubusDlg::OnDelete(){if(m_list1.GetCount()==0)//判断是否是第一个数据return;elseif(m_list1.GetCurSel()0||m_list1.GetCurSel()m_list1.GetCount())m_list1.SetCurSel(0);m_pRecordset-Delete(adAffectCurrent);//删除指针所在的数据m_pRecordset-Update();intnCurSel=m_list1.GetCurSel();//得到当前位置m_list1.DeleteString(nCurSel);if(nCurSel==0&&(m_list1.GetCount()!=0))//在最后一个位置时m_list1.SetCurSel(nCurSel);elseif(m_list1.GetCount()!=0)//在其他位置将位置向下移动一个位置m_list1.SetCurSel(nCurSel-1);………………………………………//对服务器端的Modbus数据进行操作}图5Modbus/TCP通信模型测试软件4.结束语由于Modbus/TCP协议的简单性和开放性,使得该协议得到广泛的应用。本文通过对Modbus/TCP理解运用VC作出一个简单的协议模型通信的测试软件。该软件能够满足其短时间内传输大量信息的要求,实验证明整个系统通信迅速、可靠,Modbus/TCP协议在系统通信中具有广泛的应用价值。其模型对于进一步研究为构建基于Mobbus/TCP协议的控制系统提供了具有现实意义的佐证。[参考文献][1]缪学勤.工业以太网技术的现状与发展.世界仪表与自动化,2003(10)[2]科默DE(Comer,DouglasE)著用TCP/IP进行网际互联—第三卷—客户/服务器编程与应用[M]。北京:电子工业出版社。1999[3]AnthonyJones.Window网络编程技术[M]。北京:机械工业出版社。1999[4]李凌著Winsock2网络编程实用教程[M]。北京:清华大学出版社。2003[5]MODBUS.ORG:MODBUSApplicationProtocolSpecification.兰州理工大学电气工程及信息工程学院施耐德实验室[6]AndySwales,OPENMODBUS/TCPSPECIFICATION,SchneiderElectric,1999(3)ImplementofModbus/TCPMo