TCPIP编程

一: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();
    }

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值