头文件
// TCPCustom_CE.h: interface for the CTCPCustom_CE class.
//
//
#if !defined(AFX_TCPCUSTOM_CE_H__0E8B4A18_8A99_438E_B5F6_B5985FFC117D__INCLUDED_)
#define AFX_TCPCUSTOM_CE_H__0E8B4A18_8A99_438E_B5F6_B5985FFC117D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winsock.h>
#include "TCPServer_CE.h"
class CTCPCustom_CE
{
public:
CTCPCustom_CE();
virtual ~CTCPCustom_CE();
public:
CTCPServer_CE * m_pTCPServer_CE; //引用TCP服务端监听Socket
CString m_RemoteHost; //远程主机IP地址
DWORD m_RemotePort; //远程主机端口号
SOCKET m_socket; //通讯Socket句柄
private:
HANDLE m_exitThreadEvent; //通讯线程退出事件句柄
HANDLE m_tcpThreadHandle; //通讯线程句柄
private:
//通讯线程函数
static DWORD SocketThreadFunc(PVOID lparam);
public:
//打开socket,创建通讯线程
bool Open(CTCPServer_CE *pTCPServer);
//关闭socket,关闭线程,释放Socket资源
bool Close();
//向客户端发送数据
bool SendData(const char * buf , int len);
};
#endif // !defined(AFX_TCPCUSTOM_CE_H__0E8B4A18_8A99_438E_B5F6_B5985FFC117D__INCLUDED_)
源文件:
// TCPCustom_CE.cpp: implementation of the CTCPCustom_CE class.
//
//
#include "stdafx.h"
#include "TCPServer.h"
#include "TCPCustom_CE.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
//构造函数
CTCPCustom_CE::CTCPCustom_CE()
{
//创建线程退出事件
m_exitThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
}
//析构函数
CTCPCustom_CE::~CTCPCustom_CE()
{
//关闭线程退出事件
CloseHandle(m_exitThreadEvent);
}
/*--------------------------------------------------------------------
【函数介绍】: 此线程用于监听与客户端连接的socket通讯的事件,例如当接收到数据、
连接断开和通讯过程发生错误等事件
【入口参数】: lparam:无类型指针,可以通过此参数,向线程中传入需要用到的资源。
在这里我们将CTCPCustom_CE类实例指针传进来
【出口参数】: (无)
【返回 值】: 返回值没有特别的意义,在此我们将返回值设为0。
---------------------------------------------------------------------*/
DWORD CTCPCustom_CE::SocketThreadFunc(PVOID lparam)
{
CTCPCustom_CE *pSocket;
//得到CTCPCustom类实例指针
pSocket = (CTCPCustom_CE*)lparam;
//定义读事件集合
fd_set fdRead;
int ret;
TIMEVAL aTime;
aTime.tv_sec = 1;
aTime.tv_usec = 0;
while (TRUE)
{
//收到退出事件,结束线程
if (WaitForSingleObject(pSocket->m_exitThreadEvent,0) == WAIT_OBJECT_0)
{
break;
}
//置空读事件集合
FD_ZERO(&fdRead);
//给pSocket设置读事件
FD_SET(pSocket->m_socket,&fdRead);
//调用select函数,判断是否有读事件发生
ret = select(0,&fdRead,NULL,NULL,&aTime);
if (ret == SOCKET_ERROR)
{
//触发错误事件
pSocket->m_pTCPServer_CE->OnClientError(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket,1);
//关闭socket
closesocket(pSocket->m_socket);
break;
}
if (ret > 0)
{
//判断是否读事件
if (FD_ISSET(pSocket->m_socket,&fdRead))
{
char recvBuf[1024];
int recvLen;
ZeroMemory(recvBuf,1024);
recvLen = recv(pSocket->m_socket,recvBuf, 1024,0);
if (recvLen == SOCKET_ERROR)
{
int nErrorCode = WSAGetLastError();
//触发与客户端端连接的Socket错误
pSocket->m_pTCPServer_CE->OnClientError(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket,nErrorCode);
//触发与客户端端连接的Socket关闭事件
pSocket->m_pTCPServer_CE->OnClientClose(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket);
//关闭socket
closesocket(pSocket->m_socket);
break;
}
//表示连接已经从容关闭
else if (recvLen == 0)
{
pSocket->m_pTCPServer_CE->OnClientClose(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket);
//关闭socket
closesocket(pSocket->m_socket);
break;
}
else
{
//触发与客户端端连接的Socket读事件
pSocket->m_pTCPServer_CE->OnClientRead(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket,recvBuf,recvLen);
}
}
}
}
return 0;
}
/*--------------------------------------------------------------------
【函数介绍】: 打开socket,创建通讯线程
【入口参数】: pTCPServer指向服务器端监听socket
【出口参数】: (无)
【返回 值】: TRUE:打开成功;FALSE:打开失败
---------------------------------------------------------------------*/
bool CTCPCustom_CE::Open(CTCPServer_CE *pTCPServer)
{
//创建通讯线程
m_tcpThreadHandle = CreateThread(NULL,0,SocketThreadFunc,this,0,NULL);
if (m_tcpThreadHandle == NULL)
{
closesocket(m_socket);
return FALSE;
}
//设置通讯模式为异步模式
DWORD ul= 1;
ioctlsocket(m_socket,FIONBIO,&ul);
m_pTCPServer_CE = pTCPServer;
return TRUE;
}
/*--------------------------------------------------------------------
【函数介绍】: 关闭socket,关闭线程,释放Socket资源
【入口参数】: (无)
【出口参数】: (无)
【返回 值】: TRUE:成功关闭;FALSE:关闭失败
---------------------------------------------------------------------*/
bool CTCPCustom_CE::Close()
{
//发送通讯线程结束事件
SetEvent(m_exitThreadEvent);
Sleep(1000);
//关闭Socket,释放资源
int err = closesocket(m_socket);
if (err == SOCKET_ERROR)
{
return FALSE;
}
return TRUE;
}
/*-----------------------------------------------------------------
【函数介绍】: 向客户端发送数据
【入口参数】: buf:待发送的数据
len:待发送的数据长度
【出口参数】: (无)
【返回 值】: TRUE:发送数据成功;FALSE:发送数据失败
------------------------------------------------------------------*/
bool CTCPCustom_CE::SendData(const char * buf , int len)
{
int nBytes = 0;
int nSendBytes=0;
while (nSendBytes < len)
{
nBytes = send(m_socket,buf+nSendBytes,len-nSendBytes,0);
if (nBytes==SOCKET_ERROR )
{
int iErrorCode = WSAGetLastError();
//触发socket的Error事件
m_pTCPServer_CE->OnClientError(m_pTCPServer_CE->m_pOwnerWnd,this,iErrorCode);
//触发与服务器端断开连接事件
m_pTCPServer_CE->OnClientClose(m_pTCPServer_CE->m_pOwnerWnd,this);
//关闭socket
Close();
return FALSE;
}
nSendBytes = nSendBytes + nBytes;
if (nSendBytes < len)
{
Sleep(1000);
}
}
return TRUE;
}
调用示例:
BOOL CTCPServerDlg::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 dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CenterWindow(GetDesktopWindow()); // center to the hpc screen
// TODO: Add extra initialization here
// 设置默认值
m_localPort = 5000;
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
// 客户端连接建立事件处理函数
void CALLBACK CTCPServerDlg::OnClientConnect(CWnd* pWnd,CTCPCustom_CE* pTcpCustom)
{
CTCPServerDlg * pDlg = (CTCPServerDlg*)pWnd;
CListBox * pLstConn = (CListBox*)pDlg->GetDlgItem(IDC_LSTCONN);
ASSERT(pLstConn != NULL);
pLstConn->AddString(pTcpCustom->m_RemoteHost + _T("建立连接"));
RETAILMSG(1,(TEXT("==OnClientConnect=%s \r\n"),pTcpCustom->m_RemoteHost));
gTcpSendObj = *pTcpCustom;
}
// 客户端SOCKET关闭事件处理函数
void CALLBACK CTCPServerDlg::OnClientClose(CWnd* pWnd,CTCPCustom_CE* pTcpCustom)
{
CTCPServerDlg * pDlg = (CTCPServerDlg*)pWnd;
int iIndex = 0;
CListBox * pLstConn = (CListBox*)pDlg->GetDlgItem(IDC_LSTCONN);
ASSERT(pLstConn != NULL);
iIndex = pLstConn->FindString(iIndex,pTcpCustom->m_RemoteHost + _T("建立连接"));
if (iIndex == LB_ERR)
{
return;
}
pLstConn->DeleteString(iIndex);
RETAILMSG(1,(TEXT("==OnClientClose=%s \r\n"),pTcpCustom->m_RemoteHost));
}
// 服务器端收到来自客户端的数据
void CALLBACK CTCPServerDlg::OnClientRead(CWnd* pWnd,CTCPCustom_CE* pTcpCustom,const char *buf,int len)
{
CString strRecv;
CString strLen;
strLen.Format(L"%d",len);
strRecv = buf;
CTCPServerDlg * pDlg = (CTCPServerDlg*)pWnd;
CListBox * pLstRecv = (CListBox*)pDlg->GetDlgItem(IDC_LSTRECV);
ASSERT(pLstRecv != NULL);
pLstRecv->AddString(_T("************************************"));
pLstRecv->AddString(_T("来自: ") + pTcpCustom->m_RemoteHost);
pLstRecv->AddString(_T("数据长度:")+strLen);
pLstRecv->AddString(strRecv);
RETAILMSG(1,(TEXT("===%s \r\n"),pTcpCustom->m_RemoteHost));
if (!pTcpCustom->SendData("OK",strlen("OK")))
{
AfxMessageBox(_T("发送失败"));
}
}
//客户端Socket错误事件处理函数
void CALLBACK CTCPServerDlg::OnClientError(CWnd* pWnd,CTCPCustom_CE* pTcpCustom,int nErrorCode)
{
RETAILMSG(1,(TEXT("==OnClientError=%s \r\n"),pTcpCustom->m_RemoteHost));
}
//服务器端Socket错误事件处理函数
void CALLBACK CTCPServerDlg::OnServerError(CWnd* pWnd,CTCPServer_CE* pTcpServer_CE,int nErrorCode)
{
}
// 监听按钮单击事件方法
void CTCPServerDlg::OnBtnlisten()
{
UpdateData(TRUE);
// 设置 m_tcpServer 属性
m_tcpServer.m_LocalPort = m_localPort;
m_tcpServer.m_pOwnerWnd = this;
m_tcpServer.OnClientConnect = OnClientConnect;
m_tcpServer.OnClientClose = OnClientClose;
m_tcpServer.OnClientRead = OnClientRead;
m_tcpServer.OnClientError = OnClientError;
m_tcpServer.OnServerError = OnServerError;
if (m_tcpServer.Open() <= 0)
{
AfxMessageBox(_T("监听失败"));
return;
}
CButton * pBtnListen = (CButton*)GetDlgItem(IDC_BTNLISTEN);
ASSERT(pBtnListen != NULL);
pBtnListen->EnableWindow(FALSE);
CButton * pBtnClose = (CButton*)GetDlgItem(IDC_BTNCLOSE);
ASSERT(pBtnClose != NULL);
pBtnClose->EnableWindow(TRUE);
CButton *pBtnSend = (CButton*)GetDlgItem(IDC_SendBtn);
ASSERT(pBtnSend != NULL);
pBtnSend->EnableWindow(TRUE);
}
//关闭按钮单击事件代码
void CTCPServerDlg::OnBtnclose()
{
if (m_tcpServer.Close() <=0)
{
AfxMessageBox(_T("关闭TCP服务器失败"));
return;
}
CButton * pBtnListen = (CButton*)GetDlgItem(IDC_BTNLISTEN);
ASSERT(pBtnListen != NULL);
pBtnListen->EnableWindow(TRUE);
CButton * pBtnClose = (CButton*)GetDlgItem(IDC_BTNCLOSE);
ASSERT(pBtnClose != NULL);
pBtnClose->EnableWindow(FALSE);
CButton *pBtnSend = (CButton*)GetDlgItem(IDC_SendBtn);
ASSERT(pBtnSend != NULL);
pBtnSend->EnableWindow(FALSE);
CListBox * pLstConn = (CListBox*)GetDlgItem(IDC_LSTCONN);
ASSERT(pLstConn != NULL);
CListBox * pLstRecv = (CListBox*)GetDlgItem(IDC_LSTRECV);
ASSERT(pLstRecv != NULL);
pLstConn->ResetContent();
pLstRecv->ResetContent();
}
void CTCPServerDlg::OnSendBtn()
{
// TODO: Add your control notification handler code here
if (!gTcpSendObj.SendData("Send data ok(Server)",strlen("Send data ok(Server)")))
{
AfxMessageBox(_T("发送失败"));
}
}