Windows CE 下的 TCP 客户端类

以前一直在使用 UDP 与服务器进行通讯,这次一个新的项目需要采用 TCP 来实现与服务器的通讯。

先写了一个 TCP 客户端的类,同时也做了一个服务器用于测试。先把客户端的 TCP 类代码分分享出来吧。

头文件:

 1 // CeTcpClient.h: interface for the CCeTcpClient class.  
 2 //  
 3 //////////////////////////////////////////////////////////////////////  
 4   
 5 #if !defined(AFX_CETCPCLIENT_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_)  
 6 #define AFX_CETCPCLIENT_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_  
 7   
 8 #if _MSC_VER > 1000  
 9 #pragma once  
10 #endif // _MSC_VER > 1000  
11   
12 #include <winsock.h>  
13   
14 // 连接断开  
15 typedef void (CALLBACK *ONDISCONNECT)(CWnd *);  
16 // 数据接收  
17 typedef void (CALLBACK *ONREAD)(CWnd *,const char *,int);  
18 // Socket 错误  
19 typedef void (CALLBACK *ONERROR)(CWnd *,int);  
20   
21 class CCeTcpClient  
22 {  
23 public:  
24     CCeTcpClient();  
25     virtual ~CCeTcpClient();  
26   
27 public:  
28     // 服务器 IP 地址  
29     CString  m_csRemoteHost;  
30     // 服务器端口  
31     int m_iPort;  
32       
33     // 连接断开  
34     ONDISCONNECT OnDisConnect;  
35     // 接收数据  
36     ONREAD OnRead;  
37     // 发生错误  
38     ONERROR OnError;  
39       
40 public:  
41     // 打开 Socket  
42     bool Open(CWnd *pWnd);  
43     // 关闭 Socket  
44     bool Close();  
45     // 与服务器端建立连接  
46     bool Connect();  
47     // 向服务器端发送数据  
48     bool SendData(const char *pcBuffer,int iLen);  
49   
50 private:  
51     // Socket 句柄  
52     SOCKET m_socket;  
53     // 通讯线程退出事件  
54     HANDLE m_hExitThreadEvent;  
55     // 通讯线程  
56     HANDLE m_hTcpThreadHandle;  
57     // 父窗口句柄  
58     CWnd *m_pOwnerWnd;  
59   
60 private:  
61     // 通讯线程  
62     static DWORD SocketControlThread(LPVOID lparam);  
63 };  
64   
65 #endif // !defined(AFX_TCPCLIENT_CE_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_)  

源文件:

  1 // CeTcpClient.cpp: implementation of the CCeTcpClient class.  
  2 // Leo.Zheng 2012.04.09  
  3 //////////////////////////////////////////////////////////////////////  
  4   
  5 #include "stdafx.h"  
  6 #include "TCPClient.h"  
  7 #include "CeTcpClient.h"  
  8   
  9 #ifdef _DEBUG  
 10 #undef THIS_FILE  
 11 static char THIS_FILE[]=__FILE__;  
 12 #define new DEBUG_NEW  
 13 #endif  
 14   
 15 //////////////////////////////////////////////////////////////////////  
 16 // Construction/Destruction  
 17 //////////////////////////////////////////////////////////////////////  
 18 CCeTcpClient::CCeTcpClient()  
 19 {  
 20     int iInitWSA = 0;  
 21     // 初始化 Socket, 版本: 1.1  
 22     WSADATA wsd;  
 23   
 24     iInitWSA = WSAStartup(MAKEWORD(1,1),&wsd);  
 25     if(0 != iInitWSA)  
 26     {  
 27         RETAILMSG(1,(L"[CCeTcpClient::CCeTcpClient]WSA start up failed: %d\r\n",iInitWSA));  
 28     }  
 29     // 创建线程退出事件  
 30     m_hExitThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);  
 31 }  
 32   
 33 CCeTcpClient::~CCeTcpClient()  
 34 {  
 35     // 释放 Socket  
 36     WSACleanup();  
 37     // 关闭线程退出事件  
 38     CloseHandle(m_hExitThreadEvent);  
 39 }  
 40   
 41 /* 
 42  * 功能: 打开 Socket 
 43  * 参数: pWnd 用于指定父窗口句柄 
 44  * 返回值: TRUE 成功; FALSE 失败 
 45 */  
 46 bool CCeTcpClient::Open(CWnd *pWnd)  
 47 {  
 48     ResetEvent(m_hExitThreadEvent);  
 49     m_pOwnerWnd = pWnd;  
 50       
 51     // 创建 TCP 套接字   
 52     m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
 53     if(SOCKET_ERROR == m_socket)  
 54     {  
 55         return FALSE;  
 56     }  
 57   
 58     // 创建通讯线程  
 59     m_hTcpThreadHandle = CreateThread(NULL,0,SocketControlThread,this,0,NULL);  
 60     if(NULL == m_hTcpThreadHandle)  
 61     {  
 62         closesocket(m_socket);  
 63         return FALSE;  
 64     }  
 65       
 66     return TRUE;  
 67 }  
 68   
 69 /* 
 70  * 功能: 关闭 Socket 
 71  * 参数: 无 
 72  * 返回值: TRUE 成功; FALSE 失败 
 73 */  
 74 bool CCeTcpClient::Close()  
 75 {  
 76     // 设置通讯线程结束事件  
 77     SetEvent(m_hExitThreadEvent);  
 78     Sleep(1000);  
 79   
 80     // 关闭 Socket  
 81     int iError = closesocket(m_socket);  
 82     if(SOCKET_ERROR == iError)  
 83     {  
 84         return FALSE;  
 85     }  
 86   
 87     return TRUE;  
 88 }  
 89   
 90 /* 
 91  * 功能: 与 TCP 服务器建立连接 
 92  * 参数: 无 
 93  * 返回值: TRUE 成功; FALSE 失败 
 94 */  
 95 bool CCeTcpClient::Connect()  
 96 {  
 97     struct sockaddr_in addr;  
 98     int iError = 0;  
 99     char cAnsiRemoteHost[255 + 1];  
100   
101     addr.sin_family = AF_INET;  
102     addr.sin_port = htons(m_iPort);  
103     ZeroMemory(cAnsiRemoteHost,sizeof(char) * (255 + 1));  
104     WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,m_csRemoteHost,wcslen(m_csRemoteHost),cAnsiRemoteHost,wcslen(m_csRemoteHost),NULL,NULL);  
105   
106    addr.sin_addr.s_addr = inet_addr(cAnsiRemoteHost);  
107    // 采用同步连接方式, connect 直接返回成功或是失败  
108    iError = connect(m_socket,(struct sockaddr *)&addr,sizeof(addr));  
109    if(SOCKET_ERROR == iError)   
110    {  
111        return FALSE;  
112    }  
113    // 设置通讯模式为异步模式  
114    DWORD dwMode = 1;  
115    ioctlsocket(m_socket,FIONBIO,&dwMode);  
116   
117    return TRUE;  
118 }  
119   
120 /* 
121  * 功能: 向服务器端发送数据 
122  * 参数: buf 待发送的数据 
123     len 待发送的数据长度 
124  * 返回值: TRUE 成功; FALSE 失败 
125 */  
126 bool CCeTcpClient::SendData(const char *pcBuffer,int iLen)  
127 {  
128     int iBytes = 0;  
129     int iSendBytes = 0;  
130               
131     while(iSendBytes < iLen)  
132     {  
133         iBytes = send(m_socket,pcBuffer + iSendBytes,iLen - iSendBytes,0);  
134         if(SOCKET_ERROR == iBytes)  
135         {  
136             int iErrorCode = WSAGetLastError();  
137             OnError(m_pOwnerWnd,iErrorCode);  
138             OnDisConnect(m_pOwnerWnd);  
139             //关闭 Socket  
140             Close();  
141             return FALSE;  
142         }  
143   
144         iSendBytes = iSendBytes + iBytes;  
145           
146         if(iSendBytes < iLen)  
147         {  
148             Sleep(1000);  
149         }  
150     }   
151     return TRUE;   
152 }  
153   
154 /* 
155  * 功能: 此线程用于监听 TCP 客户端通讯的事件 
156     例如: 当接收到数据、连接断开或通讯过程发生错误等事件 
157  * 参数: lparam: 可以通过此参数,向线程中传入需要用到的资源 
158     在这里我们将 CCeTcpClient 类实例指针传进来 
159  * 返回值: 无意义,将返回值设为 0。 
160 */  
161 DWORD CCeTcpClient::SocketControlThread(LPVOID lparam)  
162 {  
163     CCeTcpClient *pSocket = NULL;  
164     fd_set fdRead;  
165     TIMEVAL aTime;  
166     int iRet = 0;  
167   
168     // 得到 CCeTcpClient 实例指针  
169     pSocket = (CCeTcpClient *)lparam;  
170     // 事件等待时间设置  
171     aTime.tv_sec = 1;  
172     aTime.tv_usec = 0;  
173   
174     while(TRUE)  
175     {  
176         // 退出事件,结束线程  
177         if(WAIT_OBJECT_0 == WaitForSingleObject(pSocket->m_hExitThreadEvent,0))  
178         {  
179             break;  
180         }  
181         // 置 fdRead 为空  
182         FD_ZERO(&fdRead);  
183         // Socket 设置读事件  
184         FD_SET(pSocket->m_socket,&fdRead);  
185   
186         // 判断是否有读事件  
187         iRet = select(0,&fdRead,NULL,NULL,&aTime);  
188         if(SOCKET_ERROR == iRet)  
189         {  
190             pSocket->OnError(pSocket->m_pOwnerWnd,1);  
191             pSocket->OnDisConnect(pSocket->m_pOwnerWnd);  
192             //关闭客户端 Socket  
193             closesocket(pSocket->m_socket);  
194             break;  
195         }  
196           
197         if(iRet > 0)  
198         {  
199             if(FD_ISSET(pSocket->m_socket,&fdRead))  
200             {  
201                 char cRecvBuffer[1024 + 1];  
202                 int iRecvLength = 0;  
203   
204                 ZeroMemory(cRecvBuffer,sizeof(char) * (1024 + 1));  
205                 // 接收数据  
206                 iRecvLength = recv(pSocket->m_socket,cRecvBuffer,1024,0);   
207                 if(SOCKET_ERROR == iRecvLength)  
208                 {  
209                     int iError = WSAGetLastError();  
210                     pSocket->OnError(pSocket->m_pOwnerWnd,iError);  
211                     pSocket->OnDisConnect(pSocket->m_pOwnerWnd);  
212                     // 关闭客户端 Socket  
213                     closesocket(pSocket->m_socket);  
214                     break;  
215                 }  
216                 else if(0 == iRecvLength)  
217                 {  
218                     pSocket->OnDisConnect(pSocket->m_pOwnerWnd);  
219                     // 关闭客户端 Socket  
220                     closesocket(pSocket->m_socket);  
221                     break;  
222                 }  
223                 else  
224                 {  
225                    // 触发数据接收事件  
226                    pSocket->OnRead(pSocket->m_pOwnerWnd,cRecvBuffer,iRecvLength);  
227                 }  
228             }  
229         }  
230     }  
231   
232     return 0;  
233 }  

测试代码如下:

  1 BOOL CTCPClientDlg::OnInitDialog()  
  2 {  
  3     //m_bFullScreen = FALSE;  
  4     CDialog::OnInitDialog();  
  5       
  6     // Set the icon for this dialog.  The framework does this automatically  
  7     //  when the application's main window is not a dialog  
  8     SetIcon(m_hIcon, TRUE);         // Set big icon  
  9     SetIcon(m_hIcon, FALSE);        // Set small icon  
 10       
 11     CenterWindow(GetDesktopWindow());   // center to the hpc screen  
 12       
 13     // 初始化输入值  
 14     m_csRemoteHost = GetLocalIP();      // 在模拟器上测试时用: 客户端与服务器都运行在模拟器上  
 15     m_iRemotePort = 5000;  
 16     UpdateData(FALSE);  
 17     return TRUE;  // return TRUE  unless you set the focus to a control  
 18 }  
 19   
 20   
 21 // 连接断开  
 22 void CALLBACK CTCPClientDlg::OnDisConnect(CWnd *pWnd)  
 23 {  
 24     CTCPClientDlg *pDlg = (CTCPClientDlg *)pWnd;  
 25       
 26     CStatic *pStatus = (CStatic *)pDlg->GetDlgItem(IDC_LBLCONNSTATUS);  
 27     ASSERT(NULL != pStatus);  
 28     pStatus->SetWindowText(L"连接断开");  
 29       
 30     CButton *pBtnConn = (CButton *)pDlg->GetDlgItem(IDC_BTNCONN);  
 31     CButton *pBtnDisConn = (CButton *)pDlg->GetDlgItem(IDC_BTNDISCONN);  
 32     CButton *pBtnSendData =  (CButton *)pDlg->GetDlgItem(IDC_BTNSENDDATA);  
 33     ASSERT(NULL != pBtnConn);  
 34     ASSERT(NULL != pBtnDisConn);  
 35     ASSERT(NULL != pBtnSendData);  
 36     pBtnConn->EnableWindow(TRUE);  
 37     pBtnDisConn->EnableWindow(FALSE);  
 38     pBtnSendData->EnableWindow(FALSE);  
 39 }  
 40   
 41 // 接收的数据显示  
 42 void CALLBACK CTCPClientDlg::OnRead(CWnd *pWnd,const char *pcBuffer,int iLen)  
 43 {  
 44     CTCPClientDlg *pDlg = (CTCPClientDlg *)pWnd;  
 45     CString csRecvStr = pcBuffer;  
 46     CEdit *pEdtRecv = (CEdit *)pDlg->GetDlgItem(IDC_EDTRECV);  
 47   
 48     ASSERT(NULL != pEdtRecv);  
 49     //将接收的数据显示到接收文本框上  
 50     pEdtRecv->SetWindowText(csRecvStr);  
 51 }  
 52   
 53 // Socket 错误显示  
 54 void CALLBACK CTCPClientDlg::OnError(CWnd *pWnd,int iErrorCode)  
 55 {  
 56     CString csErrorInfo;  
 57   
 58     csErrorInfo.Format(L"%s:%d",L"客户端socket发生错误",iErrorCode);  
 59     AfxMessageBox(csErrorInfo);  
 60 }  
 61   
 62 // 建立连接  
 63 void CTCPClientDlg::OnBtnconn()   
 64 {  
 65     CStatic *pStatus = (CStatic *)GetDlgItem(IDC_LBLCONNSTATUS);  
 66     CButton *pBtnConn = (CButton *)GetDlgItem(IDC_BTNCONN);  
 67     CButton *pBtnDisConn = (CButton *)GetDlgItem(IDC_BTNDISCONN);  
 68     CButton *pBtnSendData =  (CButton *)GetDlgItem(IDC_BTNSENDDATA);  
 69       
 70     ASSERT(NULL != pStatus);  
 71     ASSERT(NULL != pBtnConn);  
 72     ASSERT(NULL != pBtnDisConn);  
 73     ASSERT(NULL != pBtnSendData);  
 74   
 75     UpdateData(TRUE);  
 76     // 设置 m_tcpClient 属性  
 77     m_tcpClient.m_csRemoteHost = m_csRemoteHost;  
 78     m_tcpClient.m_iPort = m_iRemotePort;  
 79     m_tcpClient.OnDisConnect = OnDisConnect;  
 80     m_tcpClient.OnRead = OnRead;  
 81     m_tcpClient.OnError = OnError;  
 82     // 打开客户端 socket  
 83     m_tcpClient.Open(this);  
 84       
 85     // 与服务器端连接  
 86     if(m_tcpClient.Connect())  
 87     {  
 88         pStatus->SetWindowText(L"建立连接");  
 89         UpdateData(FALSE);  
 90     }  
 91     else  
 92     {  
 93         AfxMessageBox(L"建立连接失败");  
 94         pStatus->SetWindowText(L"连接断开");  
 95         return;  
 96     }  
 97   
 98     pBtnConn->EnableWindow(FALSE);  
 99     pBtnDisConn->EnableWindow(TRUE);  
100     pBtnSendData->EnableWindow(TRUE);  
101 }  
102   
103 // 断开连接  
104 void CTCPClientDlg::OnBtndisconn()   
105 {  
106     if(m_tcpClient.Close())  
107     {  
108         CStatic *pStatus = (CStatic *)GetDlgItem(IDC_LBLCONNSTATUS);  
109         CButton *pBtnConn =(CButton*)GetDlgItem(IDC_BTNCONN);  
110         CButton *pBtnDisConn = (CButton*)GetDlgItem(IDC_BTNDISCONN);  
111         CButton *pBtnSendData = (CButton*)GetDlgItem(IDC_BTNSENDDATA);  
112   
113         ASSERT(NULL != pStatus);  
114         ASSERT(NULL != pBtnConn);  
115         ASSERT(NULL != pBtnDisConn);  
116         ASSERT(NULL != pBtnSendData);  
117   
118         pStatus->SetWindowText(L"连接断开");  
119         pBtnConn->EnableWindow(TRUE);  
120         pBtnDisConn->EnableWindow(FALSE);  
121         pBtnSendData->EnableWindow(FALSE);  
122     }  
123     else  
124     {  
125         AfxMessageBox(L"连接断开失败");  
126     }     
127 }  
128   
129 // 发送数据  
130 void CTCPClientDlg::OnBtnsenddata()   
131 {  
132     char *pcSendBuf;  
133     int iSendLength = 0;  
134     UpdateData(TRUE);  
135       
136     iSendLength = m_csSendData.GetLength();  
137     pcSendBuf = new char[iSendLength * 2];  
138     ASSERT(NULL != pcSendBuf);  
139     wcstombs(pcSendBuf,m_csSendData,iSendLength);  
140     if(!m_tcpClient.SendData(pcSendBuf,iSendLength))  
141     {  
142         AfxMessageBox(L"发送失败");  
143     }  
144     delete[] pcSendBuf;  
145     pcSendBuf = NULL;         
146 }  

 

posted @ 2016-02-22 10:15  91program  阅读(318)  评论(0编辑  收藏  举报