一:Winsock编程流程
1:对于任何基于Winsock的编程首先我们必须要初始化Winsock DLL库。
int WSAStarup( WORD wVersionRequested , LPWSADATA lpWsAData )wVersionRequested是我们要求使用的Winsock的版本。
调用这个接口函数可以帮我们初始化Winsock。
2:然后我们必须创建一个套接字(socket)。
SOCKET socket( int af , int type , int protocol );
套接字可以说是Winsock通讯的核心.Winsock通讯的所有数据传输,都是通过套接字来完成的,套接字包含了两个信息,一个是IP地址,一个是Port端口号,使用这两个信息,我们就可以确定网络中的任何一个通讯节点.
3:当我们调用了socket()接口函数创建了一个套接字后,我们必须把套接字与你需要进行通讯的地址建立联系,我们可以通过绑定函数来实现这种联系.
int bind(SOCKET s , const struct sockaddr FAR* name , int namelen ) ;
struct sockaddr_in
{
short sin_family ;
u_short sin_prot ;
struct in_addr sin_addr ;
char sin_sero[8] ;
}
就包含了我们需要建立连接的本地的地址,包括,地址族,ip和端口信息.sin_family字段我们必须把他设为AF_INET,这是告诉Winsock使用的是IP地址族.sin_prot 就是我们要用来通讯的端口号.sin_addr就是我们要用来通讯的ip地址信息。
4:在这里,必须还得提一下有关'大头(big-endian)'小头(little-endian)'.因为各种不同的计算机处理数据时的方法是不一样的,Intel 86处理器上是用'小头'形势来表示多字节的编号,就是把低字节放在前面,把高字节放在后面,而互联网标准却正好相反,所以,我们必须把主机字节转换成网络字节的顺序.Winsock API提供了几个函数.
把主机字节转化成网络字节的函数;
u_long htonl( u_long hostlong );
u_short htons( u_short hostshort );
把网络字节转化成主机字节的函数;
u_long ntohl( u_long netlong ) ;
u_short ntohs( u_short netshort ) ;
这样,我们设置ip地址,和port端口时,就必须把主机字节转化成网络字节后,才能用bind()函数来绑定套接字和地址。
5:当绑定完成之后,服务器端必须建立一个监听的队列来接收客户端的连接请求.
int listen( SOCKET s ,int backlog );
这个函数可以让我们把套接字转成监听模式.
如果客户端有了连接请求,我们还必须使用
int accept( SOCKET s , struct sockaddr FAR* addr , int FAR* addrlen );
来接受客户端的请求.
6:客户端的建立的流程则是初始化WinSock ,然后创建socket套接字,再使用
int connect( SOCKET s , const struct sockaddr FAR* name , int namelen ) ;
来连接服务端。
7:下面是一个最简单的创建服务器端和客户端的例子:
服务器端的创建 :
WSADATA wsd ;
SOCKET sListen ;
SOCKET sclient ;
UINT port = 800 ;
int iAddrSize ;
struct sockaddr_in local , client ;
WSAStartup( 0x11 , &wsd );
sListen = socket ( AF_INET , SOCK_STREAM , IPPOTO_IP ) ;
local.sin_family = AF_INET ;
local.sin_addr = htonl( INADDR_ANY ) ;
local.sin_port = htons( port ) ;
bind( sListen , (struct sockaddr*)&local , sizeof( local ) ) ;
listen( sListen , 5 ) ;
sClient = accept( sListen , (struct sockaddr*)&client , &iAddrSize ) ;
客户端的创建:
WSADATA wsd ;
SOCKET sClient ;
UINT port = 800 ;
char szIp[] = "127.0.0.1" ;
int iAddrSize ;
struct sockaddr_in server ;
WSAStartup( 0x11 , &wsd );
sClient = socket ( AF_INET , SOCK_STREAM , IPPOTO_IP ) ;
server.sin_family = AF_INET ;
server.sin_addr = inet_addr( szIp ) ;
server.sin_port = htons( port );
connect( sClient , (struct sockaddr*)&server , sizeof( server ) ) ;
8:当服务器端和客户端建立连接以后,无论是客户端,还是服务器端都可以使用
int send( SOCKET s , const char FAR* buf , int len , int flags );
int recv( SOCKET s , char FAR* buf , int len , int flags );
函数来接收和发送数据,因为,TCP连接是双向的.
9:当要关闭通讯连结的时候,任何一方都可以调用
int shutdown( SOCKET s , int how ) ;
来关闭套接字的指定功能。再调用
int closesocket( SOCKET s) ;
来关闭套接字句柄。这样一个通讯过程就算完成了。
注意:上面的代码没有任何检查函数返回值,如果你作网络编程就一定要检查任何一个Winsock API函数的调用结果,因为很多时候函数调用并不一定成功.上面介绍的函数,返回值类型是int的话,如果函数调用失败的话,返回的都是SOCKET_ERROR.
二:简单的TCPIP通讯,客户端发送什么,服务端就显示什么。
1:客户端
#include <iostream>
#include <WINSOCK2.H>
#pragma comment (lib,"ws2_32.lib")
int main()
{
WSADATA wsaData; //用于填充套接字库版本的有关信息
SOCKET ServerSocket = NULL; //服务器套接字(用于同服务器IPv4地址绑定)
SOCKADDR_IN ServerSocketAddr; //服务器的IPv4地址
int port = 9999; //要连接服务器的端口
char buf[1024]; //存储消息用
int MessageLen = 0; //返回的消息长度
//加载Winsock 2.2版本
if(WSAStartup(MAKEWORD(2,2),&wsaData) !=0)
{
std::cout<<"WSAStartup failed"<<std::endl;
return 1;
}
//创建套接字
if((ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
std::cout<<"Create ServerSocket failed with error"<<" "<<WSAGetLastError()<<std::endl;
//填写服务器IPv4信息
ServerSocketAddr.sin_family = AF_INET;
ServerSocketAddr.sin_port = htons(port);
ServerSocketAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//连接服务器
if(connect(ServerSocket,(SOCKADDR*)&ServerSocketAddr,sizeof(ServerSocketAddr)) ==SOCKET_ERROR)
std::cout<<"Connecting failed with error"<<" "<<WSAGetLastError()<<std::endl;
else
std::cout<<"Connect successing!"<<std::endl;
//发送数据,直到数据内容为"exit"则退出程序
while(strcmp(buf,"exit") != 0)
{
std::cout<<"Please input:"<<std::endl;
std::cin>>buf;
if((MessageLen = send(ServerSocket,buf,strlen(buf),0)) == INVALID_SOCKET)
std::cout<<"Send data failed with error"<<" "<<WSAGetLastError()<<std::endl;
else
std::cout<<"Send"<<" "<<MessageLen<<" "<<"byte"<<"datas"<<std::endl;;
}
closesocket(ServerSocket);
WSACleanup();
return 0;
}
2:服务端
#include <WINSOCK2.H>
#include <iostream>
#pragma comment (lib,"WS2_32.LIB")
int main()
{
WSADATA wsaData; //在加载Winsock DLL版本时被用来填充该库版本的有关信息
SOCKET ListeningSocket; //用于监听的套接字
SOCKET NewConnection = NULL; //accept函数反回的套接字,用于同connect方(客户端)连系。
SOCKADDR_IN ServerAddr; //本地(服务器)IPv4地址
SOCKADDR_IN ClientAddr; //connect方IPv4地址
int port = 9999; //本地打要打开的端口
int ClientAddrLen = sizeof(ClientAddr); //connect方IPv4地址的长度
int BufLen = 0; //接收到的信息的长度
char buf[50]; //用于存储信息
/*加载.2版本的Winsock*/
if(WSAStartup(MAKEWORD(2,2),&wsaData))
{
std::cout<<"WSAStartup failed"<<std::endl;
return 1;
}
std::cout<<"WSAStartup successing!"<<std::endl;
/*创建套接字*/
if((ListeningSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
{
std::cout<<"Create ListenSocket failed with error"<<" "<<WSAGetLastError()<<std::endl;
return 1;
}
std::cout<<"Create ListenSocket successing!"<<std::endl;
/*设置服务器IPv4地址*/
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(port);
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*绑定套接字与地址信息*/
if(bind(ListeningSocket,(SOCKADDR*)&ServerAddr,sizeof(ServerAddr)) == SOCKET_ERROR)
{
std::cout<<"Bind failed with error"<<" "<<WSAGetLastError()<<std::endl;
return 1;
}
std::cout<<"Bind successing!"<<std::endl;
/*开始监听*/
if(listen(ListeningSocket,3) == SOCKET_ERROR)
{
std::cout<<"Listen failed with error"<<" "<<WSAGetLastError()<<std::endl;
return 1;
}
else
std::cout<<"Listening..."<<std::endl;
/*接受连接*/
if((NewConnection = accept(ListeningSocket,(SOCKADDR*)&ClientAddr,&ClientAddrLen)) == INVALID_SOCKET)
std::cout<<"Accept failed with error"<<" "<<WSAGetLastError()<<std::endl;
else
std::cout<<"Accept successing!"<<std::endl;
/*接收并显示数据*/
while(strcmp(buf,"exit"))
{
BufLen = recv(NewConnection,buf,sizeof(buf),0);
buf[BufLen] = '/0';
std::cout<<buf<<std::endl;
}
/*关闭套接字*/
closesocket(ListeningSocket);
closesocket(NewConnection);
WSACleanup();
return 0;
}
三:负责的TCPIP通讯
1:客户端Socket通讯类
//定义连接断开事件
typedef void (CALLBACK* ONDISCONNECT)(void* pOwner);
//定义当有数据接收事件
typedef void (CALLBACK* ONREAD)(void* pOwner,const char * buf,DWORD dwBufLen );
//定义Socket错误事件
typedef void (CALLBACK* ONERROR)(void* pOwner,int nErrorCode);
class CTCPClient_CE
{
public:
CTCPClient_CE(void);
~CTCPClient_CE(void);
public:
//远程主机IP地址
CString m_remoteHost;
//远程主机端口
int m_port;
/*--以下客户端通讯事件--*/
//连接断开事件,回调函数
ONDISCONNECT OnDisConnect;
//接收数据事件,回调函数
ONREAD OnRead;
//发生错误事件,回调函数
ONERROR OnError;
private:
//通讯Socket句柄
SOCKET m_socket;
//通讯线程退出事件句柄
HANDLE m_exitThreadEvent;
//通讯线程句柄
HANDLE m_tcpThreadHandle;
//父对象句柄
void * m_pOwner;
//接收缓冲区
char m_recvBuf[4096];
private:
//通讯线程函数
static DWORD SocketThreadFunc(LPVOID lparam);
public:
//用于打开客户端socket
BOOL Open(void * pOwner);
public:
//用于关闭客户端socket
BOOL Close();
public:
//用于建立与TCP服务器连接
BOOL Connect();
public:
//向服务器端发送数据
BOOL SendData(const char * buf , DWORD dwBufLen);
};
//构造函数
CTCPClient_CE::CTCPClient_CE()
{
//初始化socket环境
WSADATA wsd;
WSAStartup(MAKEWORD(2,2),&wsd);
//置空缓冲区
ZeroMemory(m_recvBuf,4096);
OnDisConnect = NULL; //连接断开事件,回调函数
OnRead = NULL; //接收数据事件,回调函数
OnError = NULL; //发生错误事件,回调函数
//创建线程退出事件句柄
m_exitThreadEvent = CreateEvent(NULL,FALSE,FALSE,L"EVENT_TCP_CLIENT_THREAD");
}
//析构函数
CTCPClient_CE::~CTCPClient_CE()
{
//关闭线程退出事件句柄
CloseHandle(m_exitThreadEvent);
//释放socket资源
WSACleanup();
}
/*------------------------------------------------------------------
【函数介绍】: 此线程用于监听TCP客户端通讯的事件,例如当接收到数据、
连接断开和通讯过程发生错误等事件
【入口参数】: lparam:无类型指针,可以通过此参数,向线程中传入需要用到的资源。
在这里我们将CTCPClient_CE类实例指针传进来
【出口参数】: (无)
【返回 值】: 返回值没有特别的意义,在此我们将返回值设为。
------------------------------------------------------------------*/
DWORD CTCPClient_CE::SocketThreadFunc(LPVOID lparam)
{
CTCPClient_CE *pSocket;
//得到CTCPClient_CE实例指针
pSocket = (CTCPClient_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;
}
//置空fdRead事件为空
FD_ZERO(&fdRead);
//给客户端socket设置读事件
FD_SET(pSocket->m_socket,&fdRead);
//调用select函数,判断是否有读事件发生
ret = select(0,&fdRead,NULL,NULL,&aTime);
if (ret == SOCKET_ERROR)
{
if (pSocket->OnError)
{
//触发错误事件
pSocket->OnError(pSocket->m_pOwner,1);
}
if (pSocket->OnDisConnect)
{
//触发连接断开事件
pSocket->OnDisConnect(pSocket->m_pOwner);
}
//关闭客户端socket
closesocket(pSocket->m_socket);
break;
}
if (ret > 0)
{
//发生读事件
if (FD_ISSET(pSocket->m_socket,&fdRead))
{
ZeroMemory(pSocket->m_recvBuf,4096);
//接收数据
int recvLen = recv(pSocket->m_socket,pSocket->m_recvBuf, 4096,0);
if (recvLen == SOCKET_ERROR)
{
int iError = WSAGetLastError();
if (pSocket->OnError)
{
//触发socket错误事件
pSocket->OnError(pSocket->m_pOwner,iError);
}
if (pSocket->OnDisConnect)
{
//触发与服务器断开事件
pSocket->OnDisConnect(pSocket->m_pOwner);
}
//关闭客户端socket
closesocket(pSocket->m_socket);
break;
}
else if (recvLen == 0)
{
if (pSocket->OnDisConnect)
{
//触发与服务器端断开事件
pSocket->OnDisConnect(pSocket->m_pOwner);
}
//关闭客户端socket
closesocket(pSocket->m_socket);
break;
}
else
{
if (pSocket->OnRead)
{
//触发数据接收事件
pSocket->OnRead(pSocket->m_pOwner,pSocket->m_recvBuf,recvLen);
}
}
}
}
}
TRACE(L"客户端线程退出/n");
return 0;
}
/*-----------------------------------------------------------------
【函数介绍】: 用于打开客户端socket
【入口参数】: pOwner 用于指定父对象
【出口参数】: (无)
【返回 值】: TRUE:打开成功;FALSE:打开失败
-----------------------------------------------------------------*/
BOOL CTCPClient_CE::Open(void * pOwner)
{
//复位线程退出事件
ResetEvent(m_exitThreadEvent);
//存储父对象指针
m_pOwner = pOwner;
//创建TCP套接字
m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (m_socket == SOCKET_ERROR)
{
return FALSE;
}
//创建通讯线程
m_tcpThreadHandle = CreateThread(NULL,0,SocketThreadFunc,this,0,NULL);
if (m_tcpThreadHandle == NULL)
{
closesocket(m_socket);
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------------
【函数介绍】: 用于关闭客户端socket
【入口参数】: (无)
【出口参数】: (无)
【返回 值】: TRUE:关闭成功;FALSE:关闭失败
-----------------------------------------------------------------*/
BOOL CTCPClient_CE::Close()
{
//发送通讯线程结束事件
SetEvent(m_exitThreadEvent);
//等待秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_tcpThreadHandle,1000) == WAIT_TIMEOUT)
{
TerminateThread(m_tcpThreadHandle,0);
TRACE(L"强制终止客户端线程/n");
}
m_tcpThreadHandle = NULL;
//关闭Socket,释放资源
int err = closesocket(m_socket);
if (err == SOCKET_ERROR)
{
return FALSE;
}
return TRUE;
}
/*-----------------------------------------------------------------
【函数介绍】: 用于建立与TCP服务器连接
【入口参数】: (无)
【出口参数】: (无)
【返回 值】: TRUE:建立连接成功;FALSE:建立连接失败
------------------------------------------------------------------*/
BOOL CTCPClient_CE::Connect()
{
struct sockaddr_in addr;
int err;
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
//此处要将双字节转换成单字节
char ansiRemoteHost[255];
ZeroMemory(ansiRemoteHost,255);
WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,m_remoteHost,wcslen(m_remoteHost)
,ansiRemoteHost,wcslen(m_remoteHost),NULL,NULL);
addr.sin_addr.s_addr=inet_addr(ansiRemoteHost);
//此时采用同步连接方式,connect直接返回成功或是失败
err = connect(m_socket,(struct sockaddr *)&addr,sizeof(addr));
if (err == SOCKET_ERROR)
{
return FALSE;
}
//设置通讯模式为异步模式
DWORD ul= 1;
ioctlsocket(m_socket,FIONBIO,&ul);
return TRUE;
}
/*-----------------------------------------------------------------
【函数介绍】: 向服务器端发送数据
【入口参数】: buf:待发送的数据
dwBufLen:待发送的数据长度
【出口参数】: (无)
【返回 值】: TRUE:发送数据成功;FALSE:发送数据失败
------------------------------------------------------------------*/
BOOL CTCPClient_CE::SendData(const char * buf , DWORD dwBufLen)
{
int nBytes = 0;
int nSendBytes=0;
while (nSendBytes < dwBufLen)
{
nBytes = send(m_socket,buf+nSendBytes,dwBufLen-nSendBytes,0);
if (nBytes==SOCKET_ERROR )
{
int iErrorCode = WSAGetLastError();
//触发socket的Error事件
if (OnError)
{
OnError(m_pOwner,iErrorCode);
}
//触发与服务器端断开连接事件
if (OnDisConnect)
{
OnDisConnect(m_pOwner);
}
//关闭socket
Close();
return FALSE;
}
//累计发送的字节数
nSendBytes = nSendBytes + nBytes;
if (nSendBytes < dwBufLen)
{
Sleep(1000);
}
}
return TRUE;
}
2:客户端的操作
#include "TCPClient_CE.h"
//定义TCP 客户端接收到数据消息
#define WM_RECV_TCP_DATA WM_USER + 101
//定义TCP客户端连接断开消息
#define WM_TCP_CLIENT_DISCONNECT WM_USER + 102
ON_MESSAGE(WM_RECV_TCP_DATA,OnRecvTCPData)
ON_MESSAGE(WM_TCP_CLIENT_DISCONNECT,OnClientDisconnect)
//TCP接收数据处理函数
afx_msg LONG OnRecvTCPData(WPARAM wParam,LPARAM lParam);
//客户端连接断开消息函数
afx_msg LONG OnClientDisconnect(WPARAM wParam,LPARAM lParam);
private:
//定义CTCPClient_CE对象
CTCPClient_CE m_tcpClient;
private://回调函数
//连接断开事件处理函数
static void CALLBACK OnDisConnect(void* pOwner);
//当有数据接收事件处理函数
static void CALLBACK OnRead(void* pOwner,const char * buf,DWORD dwBufLen );
//Socket错误事件处理函数
static void CALLBACK OnError(void* pOwner,int nErrorCode);
private:
//得到本地的IP地址
CString GetLocalIP();
//连接断开事件
void CALLBACK CClientDlg::OnDisConnect(void* pOwner)
{
//得到父对象指针
CClientDlg* pThis = (CClientDlg*)pOwner;
//发送消息表示客户端连接断开
pThis->PostMessage(WM_TCP_CLIENT_DISCONNECT,0,0);
}
//数据接收事件
void CALLBACK CClientDlg::OnRead(void* pOwner,const char * buf,DWORD dwBufLen )
{
BYTE *pRecvBuf = NULL; //接收缓冲区
//得到父对象指针
CClientDlg* pThis = (CClientDlg*)pOwner;
//将接收的缓冲区拷贝到pRecvBuf种
pRecvBuf = new BYTE[dwBufLen];
CopyMemory(pRecvBuf,buf,dwBufLen);
//发送异步消息,表示收到TCP数据,消息处理完,应释放内存
pThis->PostMessage(WM_RECV_TCP_DATA,WPARAM(pRecvBuf),dwBufLen);
}
//Socket错误事件
void CALLBACK CClientDlg::OnError(void* pOwner,int nErrorCode)
{
TRACE(L"客户端socket发生错误");
}
//TCP接收数据处理函数
LONG CClientDlg::OnRecvTCPData(WPARAM wParam,LPARAM lParam)
{
CString strOldRecv = L"";
CString strRecv = L"";
//接收到的BUF
CHAR *pBuf = (CHAR*)wParam;
//接收到的BUF长度
DWORD dwBufLen = lParam;
//接收框
CEdit *pEdtRecvMsg = (CEdit*)GetDlgItem(IDC_EDT_RECV);
ASSERT(pEdtRecvMsg != NULL);
//得到接收框中的历史文本
pEdtRecvMsg->GetWindowTextW(strOldRecv);
//
strRecv = CString(pBuf);
//将新接收到的文本添加到接收框中
strOldRecv = strOldRecv + strRecv + L"/r/n";
pEdtRecvMsg->SetWindowTextW(strOldRecv);
//释放内存
delete[] pBuf;
pBuf = NULL;
return 0;
}
//客户端连接断开消息函数
LONG CClientDlg::OnClientDisconnect(WPARAM wParam,LPARAM lParam)
{
//得到状态栏标签
CStatic * pStatus = (CStatic *)GetDlgItem(IDC_LBL_CONNSTATUS);
ASSERT(pStatus != NULL);
pStatus->SetWindowText(_T("连接断开"));
return 0;
}
void CClientDlg::OnBnClickedBtnConn()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
CStatic *pStatus = (CStatic*)GetDlgItem(IDC_LBL_CONNSTATUS);
ASSERT(pStatus != NULL);
//设置m_tcpClient属性
m_tcpClient.m_remoteHost = m_remoteHost;
m_tcpClient.m_port = m_remotePort;
m_tcpClient.OnDisConnect = OnDisConnect;
m_tcpClient.OnRead = OnRead;
m_tcpClient.OnError = OnError;
//打开客户端socket
m_tcpClient.Open(this);
//建立与服务器端连接
if (m_tcpClient.Connect())
{
pStatus->SetWindowText(L"建立连接");
UpdateData(FALSE);
}
else
{
AfxMessageBox(_T("建立连接失败"));
pStatus->SetWindowText(L"连接断开");
return;
}
}
void CClientDlg::OnBnClickedBtnDisconn()
{
// TODO: Add your control notification handler code here
CStatic *pStatus = (CStatic*)GetDlgItem(IDC_LBL_CONNSTATUS);
ASSERT(pStatus != NULL);
//关闭客户端套接字
if (m_tcpClient.Close())
{
pStatus->SetWindowText(L"连接断开");
}
else
{
AfxMessageBox(_T("连接断开失败"));
}
}
void CClientDlg::OnBnClickedBtnSenddata()
{
// TODO: Add your control notification handler code here
CString strSendData;
char * sendBuf;
int sendLen=0;
CEdit *pEdtSend = (CEdit*)GetDlgItem(IDC_EDT_SEND);
pEdtSend->GetWindowTextW(strSendData);
//设置发送缓冲区
sendLen = strSendData.GetLength()*2 + 2;
sendBuf = new char[sendLen];
ZeroMemory(sendBuf,sendLen);
wcstombs(sendBuf,strSendData,sendLen);
sendLen = strlen(sendBuf)+1;
//发送数据
if (!m_tcpClient.SendData(sendBuf,sendLen))
{
AfxMessageBox(_T("发送失败"));
}
//释放内存
delete[] sendBuf;
sendBuf = NULL;
}
//得到本地的IP地址
CString CClientDlg::GetLocalIP()
{
HOSTENT *LocalAddress;
char *Buff;
TCHAR *wBuff;
CString strReturn = _T("");
//创建新的缓冲区
Buff = new char[256];
wBuff = new TCHAR[256];
//置空缓冲区
memset(Buff, '/0', 256);
memset(wBuff, TEXT('/0'), 256*sizeof(TCHAR));
//得到本地计算机名
if (gethostname(Buff, 256) == 0)
{
//转换成双字节字符串
mbstowcs(wBuff, Buff, 256);
//得到本地地址
LocalAddress = gethostbyname(Buff);
//置空buff
memset(Buff, '/0', 256);
//组合本地IP地址
sprintf(Buff, "%d.%d.%d.%d/0", LocalAddress->h_addr_list[0][0] & 0xFF,
LocalAddress->h_addr_list[0][1] & 0x00FF, LocalAddress->h_addr_list[0][2] & 0x0000FF, LocalAddress->h_addr_list[0][3] & 0x000000FF);
//置空wBuff
memset(wBuff, TEXT('/0'), 256*sizeof(TCHAR));
//转换成双字节字符串
mbstowcs(wBuff, Buff, 256);
//设置返回值
strReturn = wBuff;
}
else
{
}
//释放Buff缓冲区
delete[] Buff;
Buff = NULL;
//释放wBuff缓冲区
delete[] wBuff;
wBuff = NULL;
return strReturn;
}
3:服务端Socket操作1
class CTCPCustom_CE
{
public:
CTCPCustom_CE(void);
~CTCPCustom_CE(void);
private:
//通讯线程函数
static DWORD SocketThreadFunc(PVOID lparam);
public:
//打开socket,创建通讯线程
BOOL Open(CTCPServer_CE *pTCPServer);
//关闭socket,关闭线程,释放Socket资源
BOOL Close();
public:
//发送数据
BOOL SendData(const char * buf , DWORD dwBufLen);
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; //通讯线程句柄
};
CTCPCustom_CE::CTCPCustom_CE(void)
{
}
CTCPCustom_CE::~CTCPCustom_CE(void)
{
}
/*----------------------------------------------------------------
【函数介绍】: 此线程用于监听与客户端连接的socket通讯的事件,例如当接收到数据、
连接断开和通讯过程发生错误等事件
【入口参数】: lparam:无类型指针,可以通过此参数,向线程中传入需要用到的资源。
在这里我们将CTCPCustom_CE类实例指针传进来
【出口参数】: (无)
【返回 值】: 返回值没有特别的意义,在此我们将返回值设为。
-----------------------------------------------------------------*/
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)
{
if (pSocket->m_pTCPServer_CE->OnClientError)
{
//触发错误事件
pSocket->m_pTCPServer_CE->OnClientError(pSocket->m_pTCPServer_CE->m_pOwner,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错误
if (pSocket->m_pTCPServer_CE->OnClientError)
{
pSocket->m_pTCPServer_CE->OnClientError(pSocket->m_pTCPServer_CE->m_pOwner,pSocket,nErrorCode);
}
//触发与客户端端连接的Socket关闭事件
if (pSocket->m_pTCPServer_CE->OnClientClose)
{
pSocket->m_pTCPServer_CE->OnClientClose(pSocket->m_pTCPServer_CE->m_pOwner,pSocket);
}
//关闭socket
closesocket(pSocket->m_socket);
//移出客户端
pSocket->m_pTCPServer_CE->RemoteClient(pSocket);
break;
}
//表示连接已经从容关闭
else if (recvLen == 0)
{
if (pSocket->m_pTCPServer_CE->OnClientClose)
{
pSocket->m_pTCPServer_CE->OnClientClose(pSocket->m_pTCPServer_CE->m_pOwner,pSocket);
}
//关闭socket
closesocket(pSocket->m_socket);
//移出客户端
pSocket->m_pTCPServer_CE->RemoteClient(pSocket);
break;
}
else
{
//触发与客户端端连接的Socket读事件
if (pSocket->m_pTCPServer_CE->OnClientRead)
{
pSocket->m_pTCPServer_CE->OnClientRead(pSocket->m_pTCPServer_CE->m_pOwner,pSocket,recvBuf,recvLen);
}
}
}
}
}
TRACE(L"客户端线程退出/n");
return 0;
}
/*-----------------------------------------------------------------
【函数介绍】: 打开socket,创建通讯线程
【入口参数】: pTCPServer指向服务器端监听socket
【出口参数】: (无)
【返回 值】: TRUE:打开成功;FALSE:打开失败
------------------------------------------------------------------*/
BOOL CTCPCustom_CE::Open(CTCPServer_CE *pTCPServer)
{
CString strEvent;
strEvent.Format(L"EVENT_CLIENT_THREAD_EXIT %d",m_socket);
//创建线程退出事件
m_exitThreadEvent = CreateEvent(NULL,FALSE,FALSE,strEvent);
//创建通讯线程
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);
//等待秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_tcpThreadHandle,1000) == WAIT_TIMEOUT)
{
TerminateThread(m_tcpThreadHandle,0);
TRACE(L"强制终止客户端线程/n");
}
m_tcpThreadHandle = NULL;
//关闭句柄
CloseHandle(m_exitThreadEvent);
//关闭Socket,释放资源
int err = closesocket(m_socket);
if (err == SOCKET_ERROR)
{
return FALSE;
}
TRACE(L"客户端对象被成功关闭/n");
return TRUE;
}
/*-----------------------------------------------------------------
【函数介绍】: 向客户端发送数据
【入口参数】: buf:待发送的数据
dwBufLen:待发送的数据长度
【出口参数】: (无)
【返回 值】: TRUE:发送数据成功;FALSE:发送数据失败
------------------------------------------------------------------*/
BOOL CTCPCustom_CE::SendData(const char * buf , DWORD dwBufLen)
{
int nBytes = 0;
int nSendBytes=0;
while (nSendBytes < dwBufLen)
{
nBytes = send(m_socket,buf+nSendBytes,dwBufLen-nSendBytes,0);
if (nBytes==SOCKET_ERROR )
{
int iErrorCode = WSAGetLastError();
//触发socket的Error事件
if (m_pTCPServer_CE->OnClientError)
{
m_pTCPServer_CE->OnClientError(m_pTCPServer_CE->m_pOwner,this,iErrorCode);
}
//触发与服务器端断开连接事件
if (m_pTCPServer_CE->OnClientClose)
{
m_pTCPServer_CE->OnClientClose(m_pTCPServer_CE->m_pOwner,this);
}
//关闭socket
Close();
return FALSE;
}
nSendBytes = nSendBytes + nBytes;
if (nSendBytes < dwBufLen)
{
Sleep(1000);
}
}
return TRUE;
}
4:Socket操作类2
class CTCPCustom_CE;
class CTCPServer_CE;
//定义客户端连接建立事件
typedef void (CALLBACK* ONCLIENTCONNECT)(void* pOwner,CTCPCustom_CE*);
//定义客户端SOCKET关闭事件
typedef void (CALLBACK* ONCLIENTCLOSE)(void* pOwner,CTCPCustom_CE*);
//定义客户端当有数据接收事件
typedef void (CALLBACK* ONCLIENTREAD)(void* pOwner,CTCPCustom_CE*,const char * buf,DWORD dwBufLen );
//定义客户端Socket错误事件
typedef void (CALLBACK* ONCLIENTERROR)(void* pOwner,CTCPCustom_CE*,int nErrorCode);
//定义服务器端Socket错误事件
typedef void (CALLBACK* ONSERVERERROR)(void* pOwner,CTCPServer_CE*,int nErrorCode);
class CTCPServer_CE
{
public:
CTCPServer_CE(void);
~CTCPServer_CE(void);
public:
int m_LocalPort; //设置服务端口号
void * m_pOwner; //父对象句柄
private:
SOCKET m_ServerSocket; //TCP服务监听socket
HANDLE m_serverThreadHandle; //通讯线程句柄
HANDLE m_exitThreadEvent; //通讯线程退出事件句柄
public: //定义事件
//客户端连接建立事件,回调函数
ONCLIENTCONNECT OnClientConnect;
//客户端连接断开事件,回调函数
ONCLIENTCLOSE OnClientClose;
//客户端接收数据事件,回调函数
ONCLIENTREAD OnClientRead;
//客户端发生错误事件,回调函数
ONCLIENTERROR OnClientError;
//服务器端发生错误事件,回调函数
ONSERVERERROR OnServerError;
private:
//TCP服务器监听线程函数
static DWORD SocketThreadFunc(PVOID lparam);
public:
//删除客户端对象
void RemoteClient(CTCPCustom_CE *pClient /*客户端对象*/);
public:
//打开TCP服务
int Open();
public:
//关闭TCP服务
int Close();
public:
//发送数据
BOOL SendData(CTCPCustom_CE* pCustomCE, const char * buf , DWORD dwBufLen);
};
#include "TCPServer_CE.h"
#include "TCPCustom_CE.h"
#include <afxtempl.h>
//存储客户端Socket句柄
CPtrList m_ListClientSocket;
//构造函数
CTCPServer_CE::CTCPServer_CE()
{
//创建线程退出事件句柄
m_exitThreadEvent = CreateEvent(NULL,FALSE,FALSE,L"EVENT_SERVER_THREAD_QUIT");
//客户端连接建立事件,回调函数
OnClientConnect = NULL;
//客户端连接断开事件,回调函数
OnClientClose = NULL;
//客户端接收数据事件,回调函数
OnClientRead = NULL;
//客户端发生错误事件,回调函数
OnClientError = NULL;
//服务器端发生错误事件,回调函数
OnServerError = NULL;
}
//析构函数
CTCPServer_CE::~CTCPServer_CE()
{
//关闭线程退出事件句柄
CloseHandle(m_exitThreadEvent);
}
/*-----------------------------------------------------------------
【函数介绍】: 此线程用于检测监听套接字事件。
【入口参数】: lparam:无类型指针,可以通过此参数,向线程中传入需要用到的资源。
在这里我们将CTCPServer_CE类实例指针传进来
【出口参数】: (无)
【返回 值】: 返回值没有特别的意义,在此我们将返回值设为。
------------------------------------------------------------------*/
DWORD CTCPServer_CE::SocketThreadFunc(PVOID lparam)
{
CTCPServer_CE *pSocket;
//得到CTCPServer_CE实例指针
pSocket = (CTCPServer_CE*)lparam;
//定义读事件集合
fd_set fdRead;
int ret;
TIMEVAL aTime;
aTime.tv_sec = 1;
aTime.tv_usec = 1;
while (TRUE)
{
//收到退出事件,结束线程
if (WaitForSingleObject(pSocket->m_exitThreadEvent,0) == WAIT_OBJECT_0)
{
break;
}
FD_ZERO(&fdRead);
FD_SET(pSocket->m_ServerSocket,&fdRead);
//监听事件
ret = select(0,&fdRead,NULL,NULL,&aTime);
if (ret == SOCKET_ERROR)
{
//触发错误事件
int iErrorCode = WSAGetLastError();
//触发服务器socket的错误事件
if (pSocket->OnServerError)
{
pSocket->OnServerError(pSocket->m_pOwner,pSocket,iErrorCode);
}
//关闭服务器套接字
closesocket(pSocket->m_ServerSocket);
break;
}
if (ret > 0)
{
//判断是否读事件
if (FD_ISSET(pSocket->m_ServerSocket,&fdRead))
{
//如果调用了Listen,则表示触发了OnAccept事件
SOCKADDR_IN clientAddr;
CTCPCustom_CE * pClientSocket = new CTCPCustom_CE();
int namelen = sizeof(clientAddr);
//等待,创建与客户端连接的套接字
pClientSocket->m_socket = accept(pSocket->m_ServerSocket, (struct sockaddr *)&clientAddr, &namelen);
//接收到客户端连接
if (pClientSocket->m_socket)
{
pClientSocket->m_RemoteHost = inet_ntoa(clientAddr.sin_addr);
pClientSocket->m_RemotePort = ntohs(clientAddr.sin_port);
//触发与客户端建立连接事件
if (pSocket->OnClientConnect)
{
pSocket->OnClientConnect(pSocket->m_pOwner,pClientSocket);
}
//打开pClientSocket服务线程
pClientSocket->Open(pSocket);
//添加到客户端连接队列中
m_ListClientSocket.AddTail(pClientSocket);
}
else
{
//失败,释放内存
delete pClientSocket;
pClientSocket = NULL;
}
}
}
}
//
TRACE(L"服务器端线程退出/n");
return 0;
}
//删除客户端
void CTCPServer_CE::RemoteClient(CTCPCustom_CE *pClient /*客户端对象*/)
{
POSITION posPrior;
POSITION pos = m_ListClientSocket.GetHeadPosition();
while (pos != NULL)
{
posPrior = pos;
CTCPCustom_CE *pTcpCustom = (CTCPCustom_CE*)m_ListClientSocket.GetNext(pos);
if (pTcpCustom == pClient)
{
//释放内存
delete pTcpCustom;
pTcpCustom = NULL;
m_ListClientSocket.RemoveAt(posPrior);
TRACE(L"移出了一个客户端对象/n");
break;
}
}
}
/*------------------------------------------------------------------
【函数介绍】: 打开TCP服务
【入口参数】: (无)
【出口参数】: (无)
【返回 值】: <=0:打开TCP服务失败; =1:打开TCP服务成功
------------------------------------------------------------------*/
int CTCPServer_CE::Open()
{
WSADATA wsa;
//1.初始化socket资源
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
return -1;//代表失败
}
//2.创建监听套接字
if ((m_ServerSocket=socket(AF_INET, SOCK_STREAM, 0))<0)
{
return -2;
}
SOCKADDR_IN serverAddr;
ZeroMemory((char *)&serverAddr,sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(m_LocalPort);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//3.绑定监听套接字
if (bind(m_ServerSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr))<0)
{
return -3 ;
}
//4.监听套接字开始监听
if (listen(m_ServerSocket,8)!=0)
{
return -3;
}
//4.设置监听套接字通讯模式为异步模式
DWORD ul= 1;
ioctlsocket(m_ServerSocket,FIONBIO,&ul);
ResetEvent(m_exitThreadEvent);
//5.创建通讯线程,在线程里,等待客户端接入
m_serverThreadHandle = CreateThread(NULL,0,SocketThreadFunc,this,0,NULL);
if (m_serverThreadHandle == NULL)
{
closesocket(m_ServerSocket);
return -1;
}
return 1;
}
/*-----------------------------------------------------------------
【函数介绍】: 关闭TCP服务
【入口参数】: (无)
【出口参数】: (无)
【返回 值】: <=0:关闭TCP服务失败; =1:关闭TCP服务成功
------------------------------------------------------------------*/
int CTCPServer_CE::Close()
{
//结束通讯线程
SetEvent(m_exitThreadEvent);
//等待秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_serverThreadHandle,1000) == WAIT_TIMEOUT)
{
TerminateThread(m_serverThreadHandle,0);
TRACE(L"强制终止服务器端线程/n");
}
m_serverThreadHandle = NULL;
//关闭Socket,释放资源
int err = closesocket(m_ServerSocket);
if (err == SOCKET_ERROR)
{
return -1;
}
//首先,关闭与所有客户端连接
POSITION pos = m_ListClientSocket.GetHeadPosition();
while (pos != NULL)
{
//得到客户端对象
CTCPCustom_CE *pTcpCustom = (CTCPCustom_CE*)m_ListClientSocket.GetNext(pos);
if (!pTcpCustom->Close())
{
TRACE(L"关闭客户端socket错误");
}
//释放内存
delete pTcpCustom;
pTcpCustom = NULL;
}
m_ListClientSocket.RemoveAll();
WSACleanup();
return 1;
}
/*-----------------------------------------------------------------
【函数介绍】: 发送数据
【入口参数】: pCustomCE :客户端对象指针
buf : 缓冲区
dwBufLen : 缓冲区长度
【出口参数】: (无)
【返回 值】: TRUE : 发送成功;FALSE : 发送失败
------------------------------------------------------------------*/
BOOL CTCPServer_CE::SendData(CTCPCustom_CE* pCustomCE, const char * buf , DWORD dwBufLen)
{
BOOL bResult = FALSE;
BOOL bExisted = FALSE;
if (pCustomCE == NULL)
{
return FALSE;
}
//判断此客户端是否存在
POSITION pos = m_ListClientSocket.GetHeadPosition();
while (pos != NULL)
{
CTCPCustom_CE *pTcpCustom = (CTCPCustom_CE*)m_ListClientSocket.GetNext(pos);
if (pCustomCE == pTcpCustom)
{
bExisted = TRUE;
break;
}
}
if (!bExisted)
{
return FALSE;
}
bResult = pCustomCE->SendData(buf,dwBufLen);
if (!bResult)
{
//
RemoteClient(pCustomCE);
}
return bResult;
}
5:服务端操作类
#include "TCPServer_CE.h"
#include "TCPCustom_CE.h"
//定义通用缓冲区
typedef struct _DATA_BUF
{
DWORD dwBufLen;
char* sBuf;
TCHAR szAddress[MAX_PATH];
}DATA_BUF,*PDATA_BUF;
//定义TCP 收到客户端数据消息
#define WM_RECV_TCP_DATA WM_USER + 101
//定义TCP客户端连接消息
#define WM_TCP_CLIENT_CONNECT WM_USER + 102
ON_MESSAGE(WM_RECV_TCP_DATA,OnRecvTCPData)
ON_MESSAGE(WM_TCP_CLIENT_CONNECT,OnClientConnect)
//TCP接收数据处理函数
afx_msg LONG OnRecvTCPData(WPARAM wParam,LPARAM lParam);
//客户端连接断开消息函数
afx_msg LONG OnClientConnect(WPARAM wParam,LPARAM lParam);
private:
//定义CTCPClient_CE对象
CTCPClient_CE m_tcpClient;
private:
//定义CTCPServer_CE对象
CTCPServer_CE m_tcpServer;
private:
//客户端连接建立事件处理函数
static void CALLBACK OnClientConnect(void* pOwner,CTCPCustom_CE *pTcpCustom);
//客户端SOCKET关闭事件处理函数
static void CALLBACK OnClientClose(void* pOwner,CTCPCustom_CE*pTcpCustom);
//服务器端收到来自客户端的数据
static void CALLBACK OnClientRead(void* pOwner,CTCPCustom_CE* pTcpCustom,const char * buf,DWORD dwBufLen );
//客户端Socket错误事件处理函数
static void CALLBACK OnClientError(void* pOwner,CTCPCustom_CE* pTcpCustom,int nErrorCode);
//服务器端Socket错误事件处理函数
static void CALLBACK OnServerError(void* pOwner,CTCPServer_CE* pTcpServer_CE,int nErrorCode);
//客户端连接建立事件处理函数
void CALLBACK CServerDlg::OnClientConnect(void* pOwner,CTCPCustom_CE* pTcpCustom)
{
TCHAR *szAddress =NULL;
DWORD dwBufLen = pTcpCustom->m_RemoteHost.GetLength() + 1;
szAddress = new TCHAR[dwBufLen];
ZeroMemory(szAddress,dwBufLen*2);
//拷贝内存,得到客户端IP地址
wcscpy(szAddress,pTcpCustom->m_RemoteHost);
CServerDlg *pThis = (CServerDlg*)pOwner;
//发送异步消息,表示有客户端连接,消息处理完后,需要释放内存
pThis->PostMessage(WM_TCP_CLIENT_CONNECT,0,LPARAM(szAddress));
}
//客户端SOCKET关闭事件处理函数
void CALLBACK CServerDlg::OnClientClose(void* pOwner,CTCPCustom_CE* pTcpCustom)
{
TCHAR *szAddress =NULL;
DWORD dwBufLen = pTcpCustom->m_RemoteHost.GetLength() + 1;
szAddress = new TCHAR[dwBufLen];
ZeroMemory(szAddress,dwBufLen*2);
//拷贝内存,得到客户端IP地址
wcscpy(szAddress,pTcpCustom->m_RemoteHost);
CServerDlg *pThis = (CServerDlg*)pOwner;
//发送异步消息,表示有客户端连接,消息处理完后,需要释放内存
pThis->PostMessage(WM_TCP_CLIENT_CONNECT,1,LPARAM(szAddress));
}
//服务器端收到来自客户端的数据
void CALLBACK CServerDlg::OnClientRead(void* pOwner,CTCPCustom_CE* pTcpCustom,const char * buf,DWORD dwBufLen )
{
DATA_BUF *pGenBuf = new DATA_BUF;
char *pRecvBuf = NULL; //接收缓冲区
//得到父对象指针
CServerDlg* pThis = (CServerDlg*)pOwner;
//将接收的缓冲区拷贝到pRecvBuf种
pRecvBuf = new char[dwBufLen];
CopyMemory(pRecvBuf,buf,dwBufLen);
ZeroMemory(pGenBuf,sizeof(DATA_BUF));
pGenBuf->dwBufLen = dwBufLen;
pGenBuf->sBuf = pRecvBuf;
//
wcscpy(pGenBuf->szAddress,pTcpCustom->m_RemoteHost);
//发送异步消息,表示收到TCP数据,消息处理完,应释放内存
pThis->PostMessage(WM_RECV_TCP_DATA,WPARAM(pGenBuf),LPARAM(pTcpCustom));
}
//客户端Socket错误事件处理函数
void CALLBACK CServerDlg::OnClientError(void* pOwner,CTCPCustom_CE* pTcpCustom,int nErrorCode)
{
}
//服务器端Socket错误事件处理函数
void CALLBACK CServerDlg::OnServerError(void* pOwner,CTCPServer_CE* pTcpServer_CE,int nErrorCode)
{
}
//TCP接收数据处理函数
LONG CServerDlg::OnRecvTCPData(WPARAM wParam,LPARAM lParam)
{
DATA_BUF *pGenBuf = (DATA_BUF*)wParam; //通用缓冲区
CTCPCustom_CE* pTcpCustom= (CTCPCustom_CE* )lParam; //TCP客户端对象
//接收显示列表
CListBox * pLstRecv = (CListBox*)GetDlgItem(IDC_LST_RECV);
ASSERT(pLstRecv != NULL);
//接收到的数据
CString strRecv;
CString strLen;
strLen.Format(L"%d",pGenBuf->dwBufLen);
strRecv = CString(pGenBuf->sBuf);
pLstRecv->AddString(_T("************************************"));
pLstRecv->AddString(_T("来自: ") + CString(pGenBuf->szAddress) );
pLstRecv->AddString(_T("数据长度:")+strLen);
pLstRecv->AddString(strRecv);
//发送回应命令
if (!m_tcpServer.SendData(pTcpCustom,"recv ok",strlen("recv ok")))
{
AfxMessageBox(_T("发送失败"));
}
//释放内存
delete[] pGenBuf->sBuf;
pGenBuf->sBuf = NULL;
delete pGenBuf;
pGenBuf = NULL;
return 0;
}
//客户端连接断开消息函数
LONG CServerDlg::OnClientConnect(WPARAM wParam,LPARAM lParam)
{
int iIndex;
TCHAR *szAddress = (TCHAR*)lParam;
CString strAddrss = szAddress;
CListBox * pLstConn = (CListBox*)GetDlgItem(IDC_LST_CONN);
ASSERT(pLstConn != NULL);
if (wParam == 0)
{
pLstConn->AddString(strAddrss + _T("建立连接"));
}
else
{
iIndex = pLstConn->FindString(iIndex,strAddrss + _T("建立连接"));
if (iIndex != LB_ERR)
{
pLstConn->DeleteString(iIndex);
}
}
//释放内存
delete[] szAddress;
szAddress = NULL;
return 0;
}
//监听
void CServerDlg::OnBnClickedBtnListen()
{
UpdateData(TRUE);
//设置m_tcpServer属性
m_tcpServer.m_LocalPort = m_localPort;
m_tcpServer.m_pOwner = 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;
}
}
//关闭
void CServerDlg::OnBnClickedBtnClose()
{
CListBox * pLstConn = (CListBox*)GetDlgItem(IDC_LST_CONN);
ASSERT(pLstConn != NULL);
CListBox * pLstRecv = (CListBox*)GetDlgItem(IDC_LST_RECV);
ASSERT(pLstRecv != NULL);
//
if (m_tcpServer.Close() <=0)
{
AfxMessageBox(_T("关闭TCP服务器失败"));
return;
}
//清空列表
pLstConn->ResetContent();
pLstRecv->ResetContent();
}