Windows CE 下的 TCP 客户端类

来源:互联网 发布:ubuntu terminal 字体 编辑:程序博客网 时间:2024/05/17 02:53

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

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

头文件:

// CeTcpClient.h: interface for the CCeTcpClient class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_CETCPCLIENT_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_)#define AFX_CETCPCLIENT_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include <winsock.h>// 连接断开typedef void (CALLBACK *ONDISCONNECT)(CWnd *);// 数据接收typedef void (CALLBACK *ONREAD)(CWnd *,const char *,int);// Socket 错误typedef void (CALLBACK *ONERROR)(CWnd *,int);class CCeTcpClient{public:CCeTcpClient();virtual ~CCeTcpClient();public:// 服务器 IP 地址CString m_csRemoteHost;// 服务器端口    int m_iPort;    // 连接断开ONDISCONNECT OnDisConnect;// 接收数据ONREAD OnRead;// 发生错误ONERROR OnError;public:// 打开 Socketbool Open(CWnd *pWnd);// 关闭 Socketbool Close();// 与服务器端建立连接bool Connect();// 向服务器端发送数据bool SendData(const char *pcBuffer,int iLen);private:// Socket 句柄SOCKET m_socket;// 通讯线程退出事件HANDLE m_hExitThreadEvent;// 通讯线程HANDLE m_hTcpThreadHandle;// 父窗口句柄CWnd *m_pOwnerWnd;private:    // 通讯线程static DWORD SocketControlThread(LPVOID lparam);};#endif // !defined(AFX_TCPCLIENT_CE_H__B7856B99_69E7_4868_9BA3_96152245C65E__INCLUDED_)

源文件:
// CeTcpClient.cpp: implementation of the CCeTcpClient class.// Leo.Zheng 2012.04.09//////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "TCPClient.h"#include "CeTcpClient.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endif//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CCeTcpClient::CCeTcpClient(){int iInitWSA = 0;// 初始化 Socket, 版本: 1.1WSADATA wsd;iInitWSA = WSAStartup(MAKEWORD(1,1),&wsd);if(0 != iInitWSA){RETAILMSG(1,(L"[CCeTcpClient::CCeTcpClient]WSA start up failed: %d\r\n",iInitWSA));}// 创建线程退出事件m_hExitThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);}CCeTcpClient::~CCeTcpClient(){// 释放 SocketWSACleanup();// 关闭线程退出事件CloseHandle(m_hExitThreadEvent);}/* * 功能: 打开 Socket * 参数: pWnd 用于指定父窗口句柄 * 返回值: TRUE 成功; FALSE 失败*/bool CCeTcpClient::Open(CWnd *pWnd){ResetEvent(m_hExitThreadEvent);m_pOwnerWnd = pWnd;// 创建 TCP 套接字 m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(SOCKET_ERROR == m_socket){return FALSE;}// 创建通讯线程m_hTcpThreadHandle = CreateThread(NULL,0,SocketControlThread,this,0,NULL);if(NULL == m_hTcpThreadHandle){closesocket(m_socket);return FALSE;}return TRUE;}/* * 功能: 关闭 Socket * 参数: 无 * 返回值: TRUE 成功; FALSE 失败*/bool CCeTcpClient::Close(){// 设置通讯线程结束事件SetEvent(m_hExitThreadEvent);Sleep(1000);// 关闭 Socketint iError = closesocket(m_socket);if(SOCKET_ERROR == iError){return FALSE;}return TRUE;}/* * 功能: 与 TCP 服务器建立连接 * 参数: 无 * 返回值: TRUE 成功; FALSE 失败*/bool CCeTcpClient::Connect(){struct sockaddr_in addr;int iError = 0;char cAnsiRemoteHost[255 + 1];addr.sin_family = AF_INET;addr.sin_port = htons(m_iPort);ZeroMemory(cAnsiRemoteHost,sizeof(char) * (255 + 1));WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,m_csRemoteHost,wcslen(m_csRemoteHost),cAnsiRemoteHost,wcslen(m_csRemoteHost),NULL,NULL);   addr.sin_addr.s_addr = inet_addr(cAnsiRemoteHost);   // 采用同步连接方式, connect 直接返回成功或是失败   iError = connect(m_socket,(struct sockaddr *)&addr,sizeof(addr));   if(SOCKET_ERROR == iError)    {   return FALSE;   }   // 设置通讯模式为异步模式   DWORD dwMode = 1;   ioctlsocket(m_socket,FIONBIO,&dwMode);   return TRUE;}/* * 功能: 向服务器端发送数据 * 参数: buf 待发送的数据len 待发送的数据长度 * 返回值: TRUE 成功; FALSE 失败*/bool CCeTcpClient::SendData(const char *pcBuffer,int iLen){int iBytes = 0;int iSendBytes = 0;while(iSendBytes < iLen){    iBytes = send(m_socket,pcBuffer + iSendBytes,iLen - iSendBytes,0);if(SOCKET_ERROR == iBytes){int iErrorCode = WSAGetLastError();OnError(m_pOwnerWnd,iErrorCode);OnDisConnect(m_pOwnerWnd);//关闭 SocketClose();return FALSE;}iSendBytes = iSendBytes + iBytes;if(iSendBytes < iLen){    Sleep(1000);}} return TRUE; }/* * 功能: 此线程用于监听 TCP 客户端通讯的事件例如: 当接收到数据、连接断开或通讯过程发生错误等事件 * 参数: lparam: 可以通过此参数,向线程中传入需要用到的资源在这里我们将 CCeTcpClient 类实例指针传进来 * 返回值: 无意义,将返回值设为 0。*/DWORD CCeTcpClient::SocketControlThread(LPVOID lparam){CCeTcpClient *pSocket = NULL;fd_set fdRead;TIMEVALaTime;int iRet = 0;// 得到 CCeTcpClient 实例指针pSocket = (CCeTcpClient *)lparam;// 事件等待时间设置aTime.tv_sec = 1;aTime.tv_usec = 0;while(TRUE){        // 退出事件,结束线程if(WAIT_OBJECT_0 == WaitForSingleObject(pSocket->m_hExitThreadEvent,0)){break;}// 置 fdRead 为空FD_ZERO(&fdRead);// Socket 设置读事件FD_SET(pSocket->m_socket,&fdRead);// 判断是否有读事件iRet = select(0,&fdRead,NULL,NULL,&aTime);if(SOCKET_ERROR == iRet){pSocket->OnError(pSocket->m_pOwnerWnd,1);pSocket->OnDisConnect(pSocket->m_pOwnerWnd);//关闭客户端 Socketclosesocket(pSocket->m_socket);break;}if(iRet > 0){if(FD_ISSET(pSocket->m_socket,&fdRead)){char cRecvBuffer[1024 + 1];int iRecvLength = 0;ZeroMemory(cRecvBuffer,sizeof(char) * (1024 + 1));// 接收数据iRecvLength = recv(pSocket->m_socket,cRecvBuffer,1024,0); if(SOCKET_ERROR == iRecvLength){int iError = WSAGetLastError();pSocket->OnError(pSocket->m_pOwnerWnd,iError);pSocket->OnDisConnect(pSocket->m_pOwnerWnd);// 关闭客户端 Socketclosesocket(pSocket->m_socket);break;}else if(0 == iRecvLength){pSocket->OnDisConnect(pSocket->m_pOwnerWnd);// 关闭客户端 Socketclosesocket(pSocket->m_socket);break;}else{   // 触发数据接收事件                   pSocket->OnRead(pSocket->m_pOwnerWnd,cRecvBuffer,iRecvLength);}}}}return 0;}

测试代码如下:
BOOL CTCPClientDlg::OnInitDialog(){//m_bFullScreen = FALSE;CDialog::OnInitDialog();// Set the icon for this dialog.  The framework does this automatically//  when the application's main window is not a dialogSetIcon(m_hIcon, TRUE);// Set big iconSetIcon(m_hIcon, FALSE);// Set small iconCenterWindow(GetDesktopWindow());// center to the hpc screen// 初始化输入值m_csRemoteHost = GetLocalIP();// 在模拟器上测试时用: 客户端与服务器都运行在模拟器上m_iRemotePort = 5000;UpdateData(FALSE);return TRUE;  // return TRUE  unless you set the focus to a control}// 连接断开void CALLBACK CTCPClientDlg::OnDisConnect(CWnd *pWnd){CTCPClientDlg *pDlg = (CTCPClientDlg *)pWnd;CStatic *pStatus = (CStatic *)pDlg->GetDlgItem(IDC_LBLCONNSTATUS);ASSERT(NULL != pStatus);pStatus->SetWindowText(L"连接断开");CButton *pBtnConn = (CButton *)pDlg->GetDlgItem(IDC_BTNCONN);CButton *pBtnDisConn = (CButton *)pDlg->GetDlgItem(IDC_BTNDISCONN);CButton *pBtnSendData =  (CButton *)pDlg->GetDlgItem(IDC_BTNSENDDATA);ASSERT(NULL != pBtnConn);ASSERT(NULL != pBtnDisConn);ASSERT(NULL != pBtnSendData);pBtnConn->EnableWindow(TRUE);pBtnDisConn->EnableWindow(FALSE);pBtnSendData->EnableWindow(FALSE);}// 接收的数据显示void CALLBACK CTCPClientDlg::OnRead(CWnd *pWnd,const char *pcBuffer,int iLen){CTCPClientDlg *pDlg = (CTCPClientDlg *)pWnd;CString csRecvStr = pcBuffer;CEdit *pEdtRecv = (CEdit *)pDlg->GetDlgItem(IDC_EDTRECV);ASSERT(NULL != pEdtRecv);//将接收的数据显示到接收文本框上pEdtRecv->SetWindowText(csRecvStr);}// Socket 错误显示void CALLBACK CTCPClientDlg::OnError(CWnd *pWnd,int iErrorCode){CString csErrorInfo;csErrorInfo.Format(L"%s:%d",L"客户端socket发生错误",iErrorCode);AfxMessageBox(csErrorInfo);}// 建立连接void CTCPClientDlg::OnBtnconn() {CStatic *pStatus = (CStatic *)GetDlgItem(IDC_LBLCONNSTATUS);CButton *pBtnConn = (CButton *)GetDlgItem(IDC_BTNCONN);CButton *pBtnDisConn = (CButton *)GetDlgItem(IDC_BTNDISCONN);CButton *pBtnSendData =  (CButton *)GetDlgItem(IDC_BTNSENDDATA);ASSERT(NULL != pStatus);ASSERT(NULL != pBtnConn);ASSERT(NULL != pBtnDisConn);ASSERT(NULL != pBtnSendData);UpdateData(TRUE);// 设置 m_tcpClient 属性m_tcpClient.m_csRemoteHost = m_csRemoteHost;m_tcpClient.m_iPort = m_iRemotePort;m_tcpClient.OnDisConnect = OnDisConnect;m_tcpClient.OnRead = OnRead;m_tcpClient.OnError = OnError;// 打开客户端 socketm_tcpClient.Open(this);// 与服务器端连接if(m_tcpClient.Connect()){pStatus->SetWindowText(L"建立连接");UpdateData(FALSE);}else{AfxMessageBox(L"建立连接失败");pStatus->SetWindowText(L"连接断开");return;}pBtnConn->EnableWindow(FALSE);pBtnDisConn->EnableWindow(TRUE);pBtnSendData->EnableWindow(TRUE);}// 断开连接void CTCPClientDlg::OnBtndisconn() {if(m_tcpClient.Close()){CStatic *pStatus = (CStatic *)GetDlgItem(IDC_LBLCONNSTATUS);CButton *pBtnConn =(CButton*)GetDlgItem(IDC_BTNCONN);CButton *pBtnDisConn = (CButton*)GetDlgItem(IDC_BTNDISCONN);CButton *pBtnSendData = (CButton*)GetDlgItem(IDC_BTNSENDDATA);ASSERT(NULL != pStatus);ASSERT(NULL != pBtnConn);ASSERT(NULL != pBtnDisConn);ASSERT(NULL != pBtnSendData);pStatus->SetWindowText(L"连接断开");pBtnConn->EnableWindow(TRUE);pBtnDisConn->EnableWindow(FALSE);pBtnSendData->EnableWindow(FALSE);}else{AfxMessageBox(L"连接断开失败");}}// 发送数据void CTCPClientDlg::OnBtnsenddata() {char *pcSendBuf;int iSendLength = 0;UpdateData(TRUE);iSendLength = m_csSendData.GetLength();pcSendBuf = new char[iSendLength * 2];ASSERT(NULL != pcSendBuf);wcstombs(pcSendBuf,m_csSendData,iSendLength);if(!m_tcpClient.SendData(pcSendBuf,iSendLength)){AfxMessageBox(L"发送失败");}delete[] pcSendBuf;pcSendBuf = NULL;}


原创粉丝点击