Lớp TCP Client cho Windows CE

Trước đây tôi chủ yếu sử dụng UDP để giao tiếp với máy chủ, nhưng dự án mới này yêu cầu sử dụng TCP để thực hiện kết nối.

Tôi đã tạo một lớp TCP client và cũng xây dựng một server để kiểm thử. Dưới đây là mã nguồn của lớp TCP client:

Header file:

 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 // Kết nối ngắt kết nối  
15 typedef void (CALLBACK *ONDISCONNECT)(CWnd *);  
16 // Nhận dữ liệu  
17 typedef void (CALLBACK *ONREAD)(CWnd *,const char *,int);  
18 // Lỗi socket  
19 typedef void (CALLBACK *ONERROR)(CWnd *,int);  
20   
21 class CCeTcpClient  
22 {  
23 public:  
24     CCeTcpClient();  
25     virtual ~CCeTcpClient();  
26   
27 public:  
28     // Địa chỉ IP của máy chủ  
29     CString  m_csRemoteHost;  
30     // Cổng máy chủ  
31     int m_iPort;  
32       
33     // Ngắt kết nối  
34     ONDISCONNECT OnDisConnect;  
35     // Nhận dữ liệu  
36     ONREAD OnRead;  
37     // Lỗi xảy ra  
38     ONERROR OnError;  
39       
40 public:  
41     // Mở socket  
42     bool Open(CWnd *pWnd);  
43     // Đóng socket  
44     bool Close();  
45     // Kết nối đến máy chủ  
46     bool Connect();  
47     // Gửi dữ liệu đến máy chủ  
48     bool SendData(const char *pcBuffer,int iLen);  
49   
50 private:  
51     // Handle socket  
52     SOCKET m_socket;  
53     // Sự kiện thoát luồng giao tiếp  
54     HANDLE m_hExitThreadEvent;  
55     // Luồng giao tiếp  
56     HANDLE m_hTcpThreadHandle;  
57     // Handle cửa sổ cha  
58     CWnd *m_pOwnerWnd;  
59   
60 private:  
61     // Luồng xử lý socket  
62     static DWORD SocketControlThread(LPVOID lparam);  
63 };  
64   
65 #endif // !defined(AFX_TCPCLIENT_CE_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_)  

Source file:

  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     // Khởi tạo Socket, phiên bản: 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     // Tạo sự kiện thoát luồng  
 30     m_hExitThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);  
 31 }  
 32   
 33 CCeTcpClient::~CCeTcpClient()  
 34 {  
 35     // Giải phóng Socket  
 36     WSACleanup();  
 37     // Đóng sự kiện thoát  
 38     CloseHandle(m_hExitThreadEvent);  
 39 }  
 40   
 41 /* 
 42  * Chức năng: Mở Socket 
 43  * Tham số: pWnd dùng để xác định handle cửa sổ cha 
 44  * Trả về: TRUE thành công; FALSE thất bại 
 45 */  
 46 bool CCeTcpClient::Open(CWnd *pWnd)  
 47 {  
 48     ResetEvent(m_hExitThreadEvent);  
 49     m_pOwnerWnd = pWnd;  
 50       
 51     // Tạo socket TCP   
 52     m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
 53     if(SOCKET_ERROR == m_socket)  
 54     {  
 55         return FALSE;  
 56     }  
 57   
 58     // Tạo luồng giao tiếp  
 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  * Chức năng: Đóng Socket 
 71  * Tham số: Không có 
 72  * Trả về: TRUE thành công; FALSE thất bại 
 73 */  
 74 bool CCeTcpClient::Close()  
 75 {  
 76     // Thiết lập sự kiện kết thúc luồng  
 77     SetEvent(m_hExitThreadEvent);  
 78     Sleep(1000);  
 79   
 80     // Đóng 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  * Chức năng: Kết nối đến máy chủ TCP 
 92  * Tham số: Không có 
 93  * Trả về: TRUE thành công; FALSE thất bại 
 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    // Sử dụng phương thức kết nối đồng bộ, connect trả về thành công hoặc thất bại  
108    iError = connect(m_socket,(struct sockaddr *)&addr,sizeof(addr));  
109    if(SOCKET_ERROR == iError)   
110    {  
111        return FALSE;  
112    }  
113    // Thiết lập chế độ không đồng bộ  
114    DWORD dwMode = 1;  
115    ioctlsocket(m_socket,FIONBIO,&dwMode);  
116   
117    return TRUE;  
118 }  
119   
120 /* 
121  * Chức năng: Gửi dữ liệu đến máy chủ 
 122  * Tham số: buf dữ liệu cần gửi 
123     len độ dài dữ liệu cần gửi 
124  * Trả về: TRUE thành công; FALSE thất bại 
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             // Đóng 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  * Chức năng: Luồng này dùng để giám sát các sự kiện giao tiếp TCP 
156     ví dụ: khi nhận được dữ liệu, kết nối bị ngắt hoặc lỗi trong quá trình giao tiếp 
157  * Tham số: lparam: có thể truyền tài nguyên cần thiết vào luồng thông qua tham số này 
158     ở đây chúng ta truyền con trỏ đến đối tượng lớp CCeTcpClient  
159  * Trả về: Không có ý nghĩa, trả về 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     // Lấy con trỏ đến đối tượng CCeTcpClient  
169     pSocket = (CCeTcpClient *)lparam;  
170     // Thiết lập thời gian chờ sự kiện  
171     aTime.tv_sec = 1;  
172     aTime.tv_usec = 0;  
173   
174     while(TRUE)  
175     {  
176         // Sự kiện thoát, kết thúc luồng  
177         if(WAIT_OBJECT_0 == WaitForSingleObject(pSocket->m_hExitThreadEvent,0))  
178         {  
179             break;  
180         }  
181         // Đặt fdRead rỗng  
182         FD_ZERO(&fdRead);  
183         // Thiết lập sự kiện đọc cho socket  
184         FD_SET(pSocket->m_socket,&fdRead);  
185   
186         // Kiểm tra xem có sự kiện đọc không  
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             // Đóng socket client  
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                 // Nhận dữ liệu  
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                     // Đóng socket client  
213                     closesocket(pSocket->m_socket);  
214                     break;  
215                 }  
216                 else if(0 == iRecvLength)  
217                 {  
218                     pSocket->OnDisConnect(pSocket->m_pOwnerWnd);  
219                     // Đóng socket client  
220                     closesocket(pSocket->m_socket);  
221                     break;  
222                 }  
223                 else  
224                 {  
225                    // Kích hoạt sự kiện nhận dữ liệu  
226                    pSocket->OnRead(pSocket->m_pOwnerWnd,cRecvBuffer,iRecvLength);  
227                 }  
228             }  
229         }  
230     }  
231   
232     return 0;  
233 }  

Code kiểm thử:

  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     // Khởi tạo giá trị đầu vào  
 14     m_csRemoteHost = GetLocalIP();      // Trong môi trường mô phỏng: client và server chạy trên cùng máy ảo  
 15     m_iRemotePort = 5000;  
 16     UpdateData(FALSE);  
 17     return TRUE;  // return TRUE  unless you set the focus to a control  
 18 }  
 19   
 20   
 21 // Ngắt kết nối  
 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"Kết nối bị ngắt");  
 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 // Hiển thị dữ liệu nhận được  
 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     // Hiển thị dữ liệu nhận được lên ô văn bản  
 50     pEdtRecv->SetWindowText(csRecvStr);  
 51 }  
 52   
 53 // Thông báo lỗi socket  
 54 void CALLBACK CTCPClientDlg::OnError(CWnd *pWnd,int iErrorCode)  
 55 {  
 56     CString csErrorInfo;  
 57   
 58     csErrorInfo.Format(L"%s:%d",L"Lỗi socket client",iErrorCode);  
 59     AfxMessageBox(csErrorInfo);  
 60 }  
 61   
 62 // Kết nối đến máy chủ  
 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     // Thiết lập thuộc tính 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     // Mở socket client  
 83     m_tcpClient.Open(this);  
 84       
 85     // Kết nối đến máy chủ  
 86     if(m_tcpClient.Connect())  
 87     {  
 88         pStatus->SetWindowText(L"Đã kết nối");  
 89         UpdateData(FALSE);  
 90     }  
 91     else  
 92     {  
 93         AfxMessageBox(L"Kết nối thất bại");  
 94         pStatus->SetWindowText(L"Ngắt kết nối");  
 95         return;  
 96     }  
 97   
 98     pBtnConn->EnableWindow(FALSE);  
 99     pBtnDisConn->EnableWindow(TRUE);  
100     pBtnSendData->EnableWindow(TRUE);  
101 }  
102   
103 // Ngắt kết nối  
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"Ngắt kết nối");  
119         pBtnConn->EnableWindow(TRUE);  
120         pBtnDisConn->EnableWindow(FALSE);  
121         pBtnSendData->EnableWindow(FALSE);  
122     }  
123     else  
124     {  
125         AfxMessageBox(L"Ngắt kết nối thất bại");  
126     }     
127 }  
128   
129 // Gửi dữ liệu  
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"Gửi thất bại");  
143     }  
144     delete[] pcSendBuf;  
145     pcSendBuf = NULL;         
146 }  

Thẻ: Windows CE TCP client Socket Programming Winsock embedded systems

Đăng vào ngày 18 tháng 7 lúc 17:58