Windows CE嵌入式高级编程及其实例详解12_第1页
Windows CE嵌入式高级编程及其实例详解12_第2页
Windows CE嵌入式高级编程及其实例详解12_第3页
Windows CE嵌入式高级编程及其实例详解12_第4页
Windows CE嵌入式高级编程及其实例详解12_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第12章U DP编程 在网络高速发展和普及应用的今天,UDP已逐步发展成为一种非常重要的数据传输方式,其应用非常广泛。UDP可以用来传输实时性要求高而数据安全性又不是特别重要的数据,例如现在的网络视频、音频以及网络聊天大都是采用UDP方式进行传输。本章就重点介绍如何实现UDP编程。 本章主要包括如下内容: · UDP编程概述 · UDP编程示例121 UDP编程概述 无连接通信是通过“用户数据报协议”(User Datagram Protocol,UDP)来完成的。UDP无法保障数据的可靠传输,但能够向若干个目标发送数据,接收发自若干个源的数据。简单地说就是,如果一个客户机

2、向服务器发送数据,这一数据会立即发出,不管服务器是否已准备接收数据;如果服务器收到了客户机的数据,它不会确认收到与否。 由于不需要建立连接,所以UDP的传输效率要比TCP高,但它不能保证所有数据都准确有序地到达目的地,不保证顺序性、可靠性和无重复性。它是面向无连接的服务,以独立的信包进行传输,通信端点使用UDP对应的Internet地址。双方不需互连,按固定的最大长度进行传输,因而适用于单个报文传输。 UDP编程相对于TCP编程来说简单许多:首先调用socket函数创建数据报套接字,然后调用bind函数绑定本地地址后,接着就可以调用sendt0和recvfrom函数来直接发送数据和接收数据了。

3、在sendt0函数里参数t0直接指定了接受方的地址和端口号,而recvfrom函数里的参数from可以直接得到接收数据的来源。 UDP服务器端和客户端编程流程可参考流程图l21,该流程图简单地描述了阻塞式的UDP编程流程。122 UDP编程示例 上一节中简要介绍了UDP通讯特点以及编程方式,本节就基于SOCKET APl封装一个CUDP CE类,并通过CUDP CE类来演示双方通过UDP进行传输数据的过程。本示例将使用UDP异步通讯,并利用事件机制来判断数据的接收,具体实现步骤如下: (1)建立新项目。 使用vs2005lvc+1智能设备IMFC智能设备应用程序向导创建一个基于对话框的应用程序

4、UDPDem0,编译环境设置为Windows Mobile 6 Professional SDK(ARMV4I),设备选择CHSWindows Mobile 6 Classic Emulator,把窗口字体改成宋体小五号。盆幽幽。幽幽幽幽叠第12章UDP编程423 UDP服务器 UDP客户器调用socket(),建立数据包套 接字,返回套接字S调用socket(),建立数据包套 接字,返回套接字S + 调用bind(),将套接字S和本 地地址绑字调用bind(),将套接字S和本 地地址绑字 + 调用recvfrom接收数据 、, 阻塞等待客户数据 调用sendt0发送数据 、一, 士 调用se

5、ndt0发送数据 荔!送应0j L 调用recvfrom接收数据 + +调用closesocket0,关闭套接 字S调用closesocket0,关闭套接 字S图121 UDP服务器端和客户端编程流程图 (2)新建CUDP CE类,用于封装UDP通讯。 使用WinSockAPl函数封装一个UDP类,用于控制所有的UDP操作。CUDP CE类提供了Open方法用于打开UDP服务,同时Open方法参数里指定了UDP本地端口、UDP远程IP地址和UDP远程端口。执行Open方法,系统创建一个单独的线程,并通过select事件模型来检测UDP事件,这里主要包括数据到达事件和UDP发生错误事件;Clos

6、e方法用于关闭已打开的UDP服务;SendData方法用于向远程发送数据。CUDP CE类同时还提供了两个回调函数接口,分别为UDP接收数据事件和UDP发生错误事件。CUDP CE类图如图l22所示。 CUDP CE+m_OnUdpRecv+m_OnUdpError+Open0:lon9 +Close0:long+SendData0:long图12-2 CUDP_CE类图 下面就分步介绍CUDP CE类的创建过程。 1)定义UDP客户端发送错误回调函数和UDP接收数据回调函数,即在类CUDP CE定义文件UDP CEh里,类CUDP CE定义之前,添加如程序清单l21所示代码。 +程序清单l2

7、-i+ #include”winsockh” UDP客户端发送错误回调函数 UDP客户端接收数据回调函数 typedef void(CALLBACK+ONUDPRECV)(CWnd+,char+buf,int bufLen,sockaddr+); + 这里添加了对winsockh文件的引用,是因为UDP所用到的相关SOCKET函数以及数据结构都在此文件里被定义。 2)为CUDP CE类添加私有变量,用于定义UDP通讯句柄、远程通讯地址、线程退出事件句柄、存储父对象句柄以及接收数据缓冲区。代码片段如下: private: SOCKET m UDPSocket; UDP Socket通讯套接字 s

8、truct sockaddr in m RemoteAddr; 存储远程通讯地址 HANDLE m ExitThreadEvent; 线程退出事件 void+m pOwner; 存储父对象句柄 char m recvBuf4096, 接收数据缓冲区 接着在类构造函数里初始化这些变量,具体实现如程序清单l22所示。、 +程序清单l22 构造函数 CUDPCE:CUDPCE(void) m UDPSocket=0; UDP Socket通讯套接字 m pOwner=NULL; 存储父对象旬柄 ZeroMemory(m recvBuf,4096); 接收数据缓冲区 m OnUdpError=NULL

9、; UDP发生错误事件 m OnUdpRecv=NULL; UDP接收数据事件 ) + 3)为CUDP CE类添加数据接收和通讯错误事件,代码片段如下: public: UDP发生错误事件ONUDPERROR m_OnUdpError;UDP接收数据事件 ONUDPRECV m_OnUdpRecv; 4)为CUDP CE类添加3个全局方法,分别为“打开UDP通讯端口”方法Open、“关闭UDP通讯端口”方法Close和“发送数据”方法SendData,这3个方法将被外部调用。在使用时,将首先调用0pen方法打开UDP通讯端口,然后调用SendData方法发送数据,同时还可以调用m 回调函数来接

10、收数据,当使用完成时,再调用 方法关闭OnUdpRecv Close UDP通讯端口。这3个方法的声明如下:public:打开UDP通讯DWORD Open(voidpOwner,int localPort,LPCTSTR remoteHost ,int remotePort)j关闭UDP通讯DWORD Close(void);发送数据DWORD SendData(const char+buf,int len);Open、Close和SendData方法的实现如程序清单l 23所示。“+*程序清单l2-3"*+*+*+*+*+*函数介绍:打开UDP通讯端口+入口参数:pOwner:指

11、定父对象指针 localPort:指定远程UDP端口 romoteHost:指定远程IP地址 remotePort:指定远程UDP端口*出口参数:(无)*返回值:l代表成功;一l、一2、一3等都代表失败jDWORD CUDPCE:0pen(void+pOwner,int localPort,LPCTSTR remoteHost,int remotePort) WSADATA WSa; 传递父对象指针 m_pOwner=pOwner; 加载winsock动态链接库 if(WSAStartup(MAKEWORD(2,2),&wsa)!-0) f return一1;代表失败 ) 创建UDP套

12、接字 mUDPSocket。socket(AFINET,SOCK_DGRAM,IPPROT0UDP)j if(mUDPSocket=INVALI吐SOCKET) return-2; 设置本地地址SOCKADDRIN localAddr;localAddrsinfamily=AF_INET;localAddrsin_port=htons(10calPort)jlocalAddr-sinaddrsaddr=INADDRANY;绑定地址if(bind(m_UDPSocket,(sockaddr+)&localAddr,sizeof(10calAddr)!-0) return一3;)设置非堵塞

13、通讯DWORD ul=1jioctlsocket(mUDPSocket,FIONBl0,&u1);创建一个线程退出事件mExitThreadEvent =CreateEvent(NULL t TRUE f FALSE f NULL);创建通讯线程AfxBeginThread(RecvThread,this);设置对方地址m RemoteAddrSin family=AF INETjm RemoteAddrSin port=htons(remotePort);此处要将双字节转换成单字节char anSiRemoteHost255;ZeroMemory(ansiRemoteHoSt,255

14、);WideCharToMultiByte(CP ACP,WC COMPOSITECHECK,remoteHost,wcslen(remoteHost) ,ansiRemoteHost,WCSlen(remoteHost),NULL,NULL);m RemoteAddrsin addrs addr=inet addr(ansiRemoteHost);return l;|+*函数介绍:关闭UDP通讯端口*入口参数:(无)*出口参数:(无)+返回值:l代表成功;一l、一2等都代表失败fDWORD CUDPCE:Close(void)( 设置通讯线程退出事件,通知线程退出 SetEvent(mExi

15、tThreadEvent); Sleep(1000); 关闭线程旬柄 CloseHandle(m ExitThreadEvent)j 关闭socket if(closesocket(m UDPSocket)=SOCKETERROR) return一1; )释放socket资源if(WSACleanup()=SOCKETERROR) return一2;return l;”*函数介绍:*入口参数:发送数据buf:缓冲区数据酱糊圈圈第12章UDP编程427 Len:缓冲数据长度*出口参数:(无)+返回值:发送成功代表实际发送的字节数,否则返回一lfDWORD CUDPCE:SendData(cons

16、t char+buf,int len) int nBytes=0;每次发送出去的字节 int nSendBytes=O j 已经发送出去的字节 int nErrorCode=0;错误码 发送数据 while(nSendBytes<len) 发送数据 nBytes=sendto(m_UDPSocket,buf+nSendBytes,lennSendBytes,0,(sockaddr+)m RemoteAddr,Sizeof(m RemoteAddr); if(nBytes=SOCKETERROR) nErrorCode=WSAGetLastError()j i f(m_OnUdpError

17、) m_OnUdpError(m_pOwner,nErrorCode); ) retUrn一1;全部发送完毕 if(nSendBytes=len) break; 循环发送 Sleep(500); nSendBytes=nSendBytes+nBytes; ) return nSendBytes;)+5)为CUDP CE类添加接收数据线程函数RecvThread,该线程在UDP打开后就开始运行,到关闭UDP后退出。RecvThread线程函数用于实时检测是否有UDP数据到达,实现实时异步数据读取。该线程函数定义如下: private: 通讯线程函数StatiC UINT RecvThread(L

18、PVOIDRecvThread函数的具体实现如程序清单iparam);124所示。程序清单l24+p+函数介绍:接收线程函数*入口参数:iparam:指传进线程的参数*出口参数:(无)*返回值:、无意义。fUINT CUDP CE:RecvThread(LPVOID iparam)( 川 CUDP CE*pSocket=(CUDPCE+)iparam; fd set fdRead; int ret; TIMEVAL aTime j aTimetv sec=1; aTimetv usec=0; SOCKADDR IN tmpAddr; int tmpRecVLen; 。 int recvLen;

19、 int iErrorCode;while(TRUE) 收到退出事件,结束线程 if fwaitF。rSingleObj ect(pSocket->m_ExitThreadEvent,O)=WAIT_OBJECT 0) ( break; ) 将set初始化为空集合 FD ZERO(&fdRead); 藉pSocket一>mUDPSocket套接字添加到集合中 FD SET(pSocket->mUDPSocket,&fdRead); 调用select函数,判断套接字Il0状态 ret:select(0,fdRead,NULL,NULL,&aTime);

20、if(ret=SOCKETERROR) iErrorCode =WSAGetLastError(); if(pSocket一>m_OnUdpError) oSocket一>m OnUdpError(pSocket一>m pOwner,iErrorCode); break; 有事件发生if(ret>0)收到数据if(FDISSET(pSocket一>mUDPSocket,fdRead), f f tmpAddrsinfamily=AFINET; tmpAddr·sin_port 2 htons(pSocket一>mRemoteAddrsin_port

21、); tmpAddrsin addrs addr=INADDR ANY; tmpRecvLen=sizeof(tmpAddr)j 置空接收缓冲区 ZeroMemory(pSocket一>m recvBuf,4096); 接收数据 recvLen 2 recvfrom(pSocket一>m_UDPSocket,pSocket一>m_recvBuf,4096,0,(SOCKADDR+)&tmpAddr,&tmpRecvLen); i f f recvLen=SOCKET ERROR) f iErrorCode=WSAGetLastError()j if(pSock

22、et。>m_OnUdpError) pSocket一>m_OnUdpError(pSocket一>m_pOwner,iErrorCode); else if(recvLen=0) iErrorCode=WSAGetLastError(); if(pSocket一>m OnUdpError) pSocket一>m_OnUdpError(pSocket一>m_pOwner,iErrorCode); ) else 调用回调函数将数据发送出去 if(pSocket>m_OnUdpRecv) f pSocket一>m_OnUdpRecv(pSocket一&

23、gt;m_pOwner,pSocket一>m_recvBuf,recvLen,(SOCKADDR*)&tmpAddr)j ) TRACE(L”The read thread had exitedn-·)jWindows CE嵌入式高级编程及其实例详解(用c+实现) return 0;)+至此,CUDP CE类就设计完成了,下面就来看看CUDP CE类的使用效果。(3)设计主对话框,实现UDP通讯。1)设计如图l23所示的主对话框。 图123使用CUDP_CE类示例界面窗体上的主要控件及其属性设置如表l21所示。表121 CUDP CE类使用例子界面控件及其属性设置表 控

24、制lD 备注IDCEDITREMOTEHOST编辑框,用于输入远程lP地址,对应成员变量:mRemoteHost,类型CString IDCEDITREMOTEPORT编辑框,用于输入远程端121,对应成员变量:mRemotePort,类型int IDCEDl0CALPORT编辑框,用于输入本地端口,对应成员变量:m_LocalPort,类型int IDCBTN0PEN按钮,标题设为“打开”,用于打开UDP服务IDCBTNCLOSE按钮,标题设为“关闭”,用于关闭UDP服务IDCB刀吐SEND按钮,标题设为“发送”,用于发送数据IDCEDTSEND编辑框,用于输入发送的字符串IDCEDTREC

25、V编辑框,用于显示接收到的字符串 2)在CUDPDemoDl9类中添加CUDP CE类私有变量。代码片段如下: private: 定义UDP通讯类变量 CUDPCE mCEUdp j 注意:在UDPDEMODl9h文件要引用UDP CEh,因为这里使用到了CUDP CE类。 3)添加“打开”、“关闭”和“发送数据”按钮的单击事件代码。“打开”按钮用于打开指定的UDP服务端口,基于此端口可以进行UDP数据报的发送和接收;“关闭”按钮用于关闭打开的UDP端口,释放相关资源;“发送数据”用于向指定的远程地址和端口发送数据。 这3个事件函数的实现如程序清单l25所示。+程序清单l25 f f瓠开UDP

26、 void CUDPDemoDl9:0nBnClickedBtnOpen() UpdateData(TRUE); m_CEUdpm_OnUdpRecv=OnUdpCERecv; mCEUdpm_OnUdpError=OnUdpCEError; DWORD nResult。mCEUdpOpen(this,m_LocalPort,m_RemoteHostGetBuffer(m_RemoteHostGetLength(),mRemotePort)j if(nResult<=O) AfxMessageBox(一T(”打开端口失败); ) 关闭UDPvoid CUDPDemoDl9:0nBnCl

27、ickedBtnClose() mCEUdpClose()j发送数据void CUDPDemoDl9:0nBnClickedBtnSend() char+buf=NULL; 定义发送缓冲区 DWORD dwBufLen=0j 定义发送缓冲区长度 CString strSend=L”:得到发送输入框CEdit+pEdtSendMs92(CEdit+)GetDlgItem(IDCEDTSEND);ASSERT(pEdtSendMsg!=NULL);得到待发送的字符串pEdtSendMs9一>GetWindowTextW(strSend)? 将待发送的字符串转换成单字节,进行发送 buf=ne

28、w charStrSendGetLength()+2+1; ZeroMemory(buf,strSendGetLength()+2+1); 转换成单字节进行发送 WideCharToMultiByte(CP ACP,WC COMPOSITECHECK,StrSendGetBuffer(strSendGetLength() ,strSendGetLength(),buf,strSendGetLength()+2,NULL,NULL);dwBufLen=strlen(buf)+1, 432 Windows CE嵌入式高级编程及其实例详解(用c+实现)发送数据m_CEUdpSendData(buf,

29、dwBufLen);释放内存delete】bufjbuf=NULL; 4)在CUDPDemoDl9类中添加两个UDP事件函数,分别为数据接收事件和通讯错误事件。在数据接收事件函数里,将接收到的数据,通过Windows消息发送给主窗口,由主窗口消息处理函数,显示接收到的UDP数据。这两个事件函数的定义如下: private: UDP接收数据事件 static void CALLBACK OnUdpCERecv(void+pOwner,char+buf,DWORDdwBufLen,sockaddr+addr); UDP通讯错误事件 static void CALLBACK OnUdpCEError

30、(void+pOwner,int nErrorCode); 。 它们的实现如程序清单l26所示。 程序清单l26+ UDP数据接收回调函数 void CALLBACK CUDPDemoDl9:0nUdpCERecv(void +pOwner,char+ buf,DWORDdwBufLen,sockaddr+addr) BYTE*pRecvBuf=NULLj接收缓冲区 得到父对象指针 CUDPDemoDl9pThis=(CUDPDemoDlg+)pOwnerj 将接收的缓冲区拷贝到pRecvBuf中 pRecvBuf=new BYTEdwBufLen; CopyMemory(pRecvBuf,b

31、uf,dwBufLen);发送异步消息,表示收到串口数据,消息处理完,应释放内存pThis一>PostMessage(WMRECV_UDPDATA,WPARAM(pRecvBuf),dwBufLen);UDP报错回调函数void CALLBACK CUDPDemoDl9:0nUdpCEError(voidpOwner,int nErrorCode)f ) + 5)实现WM RECV UDP_DATA消息处理函数。OnRecvUdpData回调函数中,将接收到的数据,通过WindowS消息异步发送出去。这样就需要在CUDPDemoDl9对话框中,实现此消息处理,将接收到的数据显示到主窗体的接收框中。 第l2章UDP编程433首先在UDPDemoDl9h文件中添加UDP接收数据消息WM RECV UDP DATA消息常量定义。#define WMRECVUDPDATA WMUSER+101然后,为CUDPDemoDl9类添加如下自定义消息处理函数定义:UDP接收数据处理函数afx msg LONG OnRecVUdpData(WPARAM wParam,LPARAM lParam)j备注:该定义可添加在DECLAREMESSAGE_MAP0语句之前。OnRecvUdpData函数的实现如程序清单l

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论