zoukankan      html  css  js  c++  java
  • 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
    ",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 }  
  • 相关阅读:
    avalov+require实现tab栏
    动态加载js,css
    Zepto.js
    Linux 的文件和目录管理类命令
    shell 的基本理解
    Linux 日期时间命令
    Linux 关机命令
    type 命令
    命令类型即使用帮助
    cd 命令
  • 原文地址:https://www.cnblogs.com/91program/p/5206285.html
Copyright © 2011-2022 走看看