16.5 MFC WinSocket实例

来源:互联网 发布:阿里云服务器配置教程 编辑:程序博客网 时间:2024/05/07 08:31


本节中以一个实例,说明MFC WinSocket使用实例。此实例包含两个程序,一个是服务器端,一个是客户端。一个服务器可以接受多个客户端的连接,并可以向客户端发送数据。下面是服务器端套接字的源代码。

  1. class CSocketServer : public CAsyncSocket   // 服务器端SOCKET  
  2. {  
  3. public:  
  4.         CSocketServer();                    // 声明构造函数  
  5.         virtual ~CSocketServer();           // 声明析构函数  
  6. public:  
  7.         void DeleteRemoteSocket(CSocketClient*
    pSock);  // 删除客户端连接  
  8.         POSITION GetRemoteSocketPos(CSocketClient* pSock);  
  9.         // 获取指定客户端在链表中的位置  
  10.         CSocketClient* GetRemoteSocket(int pSock);  
  11.         // 获取SOCKET对应的客户端变量  
  12.         CPtrList m_clientList;              
    // 客户端SOCKET链表  
  13.         HWND  m_hMsgWnd;                    
    // 接收消息的窗口句柄对象  
  14. }; 

上面是服务器端SOCKET的头文件,其中定义了CSocketServer类,此类继承自CAsyncSocket类。下面是此类的实现代码。

  1. CSocketServer::CSocketServer()             
    // 定义服务器端SOCKET类的构造函数  
  2. {  
  3. }  
  4. CSocketServer::~CSocketServer()         // 定义服务
    器端SOCKET类的析构函数  
  5. {  
  6.     while (!m_clientList.IsEmpty())     // 如果客户端链表不为空  
  7.     {  
  8.         CSocketClient* client=(CSocketClient*)m_
    clientList.Remove               Head();              
    // 获取首个客户端对象  
  9.         Client->Close();                    // 关闭客户端  
  10.         delete client;                      // 删除客户端  
  11.     }  
  12.     m_clientList.RemoveAll();               // 移除所有客户端  
  13.     if (m_hSocket!=INVALID_SOCKET)  Close();  
  14.         // 如果SOCKET句柄有效,关闭  
  15. }  
  16. void CSocketServer::OnAccept(int nErrorCode)    // 接收客户端回调函数  
  17. {  
  18.     char* pLog=new char[200];                   // 定义消息日志  
  19.     if (nErrorCode)                             // 如果发生错误  
  20.     {  
  21.         if (nErrorCode==WSAENETDOWN)            // 如果错误是网络故障  
  22.             sprintf(pLog, "网络故障!");         // 显示网络故障消息提示框  
  23.         else sprintf(pLog, "FD_ACCEPT未知错误");  
  24.             // 否则,显示其他错误提示  
  25.         return;// 函数返回  
  26.     }  
  27.     else    // 如果没有发生错误  
  28.     {  
  29.         sockaddr address;                       // 定义地址变量  
  30.         CString IPaddr;                         // 定义IP地址字符串  
  31.         UINT port;                              // 定义端口号  
  32.         int address_len;                        // 定义地址长度  
  33.         address_len=sizeof(address);            // 获取地址长度  
  34.         CSocketClient* pSocket=new CSocketClient();  
  35.             // 创建CSocketClient对象  
  36.         pSocket->m_hMsgWnd=this->m_hMsgWnd;  
  37.         // 为对象的消息接收句柄变量赋值  
  38.         if (this->Accept(*pSocket,&address,&address_len))  
  39.         // 接收客户端连接,如果成功则  
  40.         {  
  41.             pSocket->AsyncSelect(FD_WRITE|FD_READ|FD_CLOSE);  
  42.         // 设置读写关闭事件  
  43.             pSocket->GetPeerName(IPaddr,port);  
  44.         // 获取客户端IP地址和端口号  
  45.             pSocket->m_strIP=IPaddr;        // 赋值SOCKETIP地址参数  
  46.             m_clientList.AddTail(pSocket);  // 将客户端对象增加到链表中  
  47.             sprintf(pLog, "接收客户端连接。IP=%s;端口=%d", IPaddr, port);  
  48.         }  
  49.         else                                // 接收客户端连接失败  
  50.         {  
  51.             int Error=GetLastError();       // 获取错误代码  
  52.             if (Error==WSAECONNREFUSED)     // 如果错误为网络错误  
  53.                 sprintf(pLog, "拒绝连接");  // 显示错误消息框  
  54.             else                            // 如果错误为其他错误  
  55.             {  
  56.                 wsprintf(pLog,"WSAAccept失败,错误代码: %d",Error);  
  57.         // 格式化消息串  
  58.             }  
  59.             delete pSocket;                 // 删除SOCKET对象  
  60.             return;                         // 函数返回  
  61.         }  
  62.     }  
  63.     CAsyncSocket::OnAccept(nErrorCode); // 调用基类的OnAccept()函数  
  64. }  
  65. void CSocketServer::OnClose(int nErrorCode)     
    // 关闭SOCKET的回调函数  
  66. {  
  67.         while (!m_clientList.IsEmpty())     // 如果客户端链表不为空  
  68.         {  
  69.         CSocketClient* client=(CSocketClient*)m_
    clientList.RemoveHead();            // 获取首个客户端对象  
  70.         Client->Close();                        // 关闭客户端  
  71.         delete client;                          // 删除客户端  
  72.     }  
  73.     m_clientList.RemoveAll();                   // 移除所有客户端  
  74.     if (m_hSocket!=INVALID_SOCKET)  Close();  
  75.             // 如果SOCKET句柄有效,关闭  
  76.     CAsyncSocket::OnClose(nErrorCode);         
    // 调用基类的OnClose()函数  
  77. }  
  78. void CSocketServer::DeleteRemoteSocket(CSocketClient* pSock)  
  79.             // 删除指定客户端连接对象  
  80. {  
  81.     pSock->Close();                             // 关闭SOCKEt连接  
  82.     POSITION pos=m_clientList.GetHeadPosition();  
  83. // 获取客户端对象链表中的第一个对象位置  
  84.     POSITION temp;                  // 定义临时变量,用于存放位置  
  85.     while(pos!=NULL)                // 如果首个客户端对象的位置有效  
  86.     {  
  87.         temp=pos;                   // 保存首个客户端对象的位置  
  88.         // 定义到下一个位置,并返回客户端对象  
  89.         CSocketClient* client= (CSocketClient*)m_
    clientList.GetNext(pos);  
  90.         if (client==pSock)          // 如果返回的客户端对象与参数一致  
  91.         {  
  92.             m_clientList.RemoveAt(temp);        // 移除客户端对象  
  93.             client->Close();                    // 关闭SOCKEt连接  
  94.             delete client;                      // 删除客户端  
  95.             break;                              // 退出循环  
  96.         }  
  97.     }  
  98.     return ;// 处理完,函数返回  

上面代码是处理服务器端SOCKET的实现,主要处理ACCEPT事件,接收到OnAccept事件后,会接收客户端连接并存入链表。下面代码是客户端SOCKET的实现。

  1. CSocketClient::CSocketClient()                 
    // 客户端SOCKET类的构造函数  
  2. {  
  3.     m_nLength=0;                               
    // 数据长度初始化为0  
  4.     memset(m_szReceBuf,0,sizeof(m_szReceBuf)); 
    // 初始化接收缓冲区  
  5.     memset(m_szSendBuf,0,sizeof(m_szSendBuf)); 
    // 初始化发送缓冲区  
  6.     m_bConnect=false;                           
    // 初始化连接状态变量为false  
  7.     m_hWnd=NULL;                              
    // 初始化窗口句柄为NULL  
  8.     m_strHost.Empty();                        
    // 初始化主机字符串为空  
  9.     m_strIP.Empty();                          
    // 初始化IP字符串为空  
  10. }  
  11. CSocketClient::~CSocketClient()             
    // 客户端SOCKET类的析构函数  
  12. {  
  13.     if (m_hSocket!=INVALID_SOCKET)  Close();  
    // 如果SOCKET句柄有效,则关闭  
  14. }  
  15. void CSocketClient::OnSend(int nErrorCode)  // 发送数据  
  16. {  
  17.     int nSendBytes = Send(m_szSendBuf,strlen(m_szSendBuf),0);  
  18.             // 发送发送缓冲区中的数据  
  19.     char* pLog=new char[200];                   // 定义消息变量  
  20.     sprintf(pLog, "服务器发送%d个数据", nSendBytes);  
    // 格式化消息内容  
  21.     if (m_hWnd!=NULL)                      
    // 如果窗体不为空,发送日志显示消息  
  22.         m_hWnd->SendMessage(WM_SOCKET_LOG,
    (WPARAM)pLog, strlen(pLog));  
  23.     memset(m_szSendBuf,0,sizeof(m_szSendBuf)); 
    // 重新初始化发送缓冲区  
  24.     AsyncSelect(FD_READ|FD_CLOSE);              // 设置读和关闭事件  
  25. }  
  26. void CSocketClient::OnReceive(int nErrorCode)     
    // 接收数据  
  27. {  
  28.     m_nLength=Receive((void*)m_szReceBuf,MAXSOCKBUF,0); // 接收数据  
  29.     m_szReceBuf[m_nLength]=0;              
    // 设置接收缓冲区最后一位为0  
  30.     char* recvBuf = new char[MAXSOCKBUF];   // 定义数组变量  
  31.     sprintf(recvBuf,(const char*)&m_szReceBuf, m_nLength);  
  32.     // 复制接收的数据  
  33.     if (m_hWnd!=NULL)                   // 如
    果日志窗体不为空,发送日志显示消息  
  34.         m_hWnd->SendMessage( WM_SOCKET_RECEIVE,
    (WPARAM)recvBuf, strlen      (recvBuf));  
  35.     memset(m_szReceBuf,0,sizeof(m_szReceBuf));      
    // 重新初始化接收缓冲区  
  36.     CAsyncSocket::OnReceive(nErrorCode);    // 调用
    基类的OnReceive()函数  
  37. }  
  38. void CSocketClient::OnConnect(int nErrorCode)       // 连接函数  
  39. {  
  40.     char* pLog=new char[200];           // 定义消息变量  
  41.     if (nErrorCode == 0)                // 如
    果错误代码为0,即没发生错误  
  42.     {  
  43.         sprintf(pLog, "连接服务器成功");   // 复制
    消息提示道消息变量中  
  44.         m_bConnect = true;              // 设置
    连接状态变量为true  
  45. }  
  46.     else sprintf(pLog, "连接服务器失败,错误代码=%d", nErrorCode);  
  47.     // 格式化错误提示信息  
  48.     if (m_hWnd!=NULL)                   // 如果日
    志窗体不为空,发送日志显示消息  
  49.         m_hWnd->SendMessage(WM_SOCKET_LOG, 
    (WPARAM)pLog, strlen(pLog));  
  50. }  
  51. void CSocketClient::Init()              // 客户端SOCKET初始化  
  52. {  
  53.     memset(m_szReceBuf,0,sizeof(m_szReceBuf));  
    // 初始化接收缓冲区  
  54.     m_nLength=MAXSOCKBUF;               // 设
    置每次接收的数据长度  

上面代码分别处理了客户端SOCKET的函数,主要处理客户端SOCKET连接、发送数据、接收数据和关闭连接等操作。客户端程序、服务器程序的运行效果分别如图16-2、图16-3所示。

 (点击查看大图)图16-2  客户端SOCKET运行效果图
原创粉丝点击