您的位置:首页 > 理论基础 > 计算机网络

TCPIP编程

2009-09-01 17:16 113 查看
一: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();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: