服务器与客户机互传消息

一、 服 务 器 程 序

  1. 创 建 一 个 名 为“server" 的 项 目, 单 文 档 界 面。
  2. 在serverview.h 中 加 入 代 码:
               #include “winsock.h"
          添 加 变 量:
                CSize       sizeTotal;// 控 制 滚 动 条
                int   count;// 信 息 条 数
                CString m_data[1000];// 信 息 存 放
                char    Hostname[260];
                char  Hostaddress[20];// 主 机IP 地 址
                SOCKET      m_sock;
                HANDLE      m_hListenThread;// 线 程
                BOOL  m_bInitialized;// 是 否 初 始 化
                WSADATA     WSAData;
                BOOL  flag;
                SOCKADDR_IN saClnt;
                int   saClntLen;
                BOOL  Isconnect;// 是 否 连 接    
    
  3. 在serverview.cpp 中 重 载CServerView() 构 造 器, 创 建 并 绑 定 嵌 套 字:
          CServerView::CServerView()
    {     // TODO: add construction code here
          Isconnect=FALSE;
          flag=FALSE;
          sizeTotal.cy=350;
          sizeTotal.cx=300;
          m_hListenThread;
          count=5;
          int status;
          WSADATA wsaData;
       m_data[0]=“initializing Windows Sockets DLL....";
          if((status=WSAStartup(0x0101, &wsaData))==0)
          {     m_data[0] +=“Succeeded";
                m_bInitialized=TRUE;
          }
          else
          {     m_bInitialized=FALSE;
          }
          m_sock=socket(AF_INET,SOCK_DGRAM,0);
          m_data[1]=“Creating socket....";
          if(m_sock==INVALID_SOCKET)
          {     m_data[1] +=“Failed";
          }
          m_data[1] +=“Succeeded";
          m_data[2]=“Binding socket....";
          sockaddr_in sa;
          sa.sin_family=AF_INET;
          sa.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
          sa.sin_port=htons(5050);
          if(bind(m_sock,(PSOCKADDR) 
         &sa,sizeof(sa))==SOCKET_ERROR)
          {     m_data[2] +=“Failed";
                closesocket(m_sock);
          }
          m_data[2] +=“Succeeded";
          m_data[3]=“Creating listener thread....";
          unsigned long idThread;
     m_hListenThread=CreateThread(NULL,0,
    (LPTHREAD_START_ROUTINE)Listen,
    (void        if(m_hListenThread)
          {     m_data[3] +=“Succeeded";
                m_data[4] +=“Listening....";
          }
          else
                m_data[4] +=“Failed";
    } 
    
  4. 在 析 构 函 数 中 完 成 必 需 的 清 除 操 作:
          CServerView:: ~CServerView()
    {     if(m_bInitialized)
          WSACleanup();
          closesocket(m_sock);
          if(m_hListenThread)
          ::TerminateThread(m_hListenThread,0);
    }     
    
  5. 定 义 接 收 和 处 理 消 息 的 线 程:
          long WINAPI Listen(CServerView *pView)
    {     char msg[2000]=“";
          int   nchar;
          SOCKADDR_IN saClnt;
          int saClntLen;
          while(1)
          { saClntLen=sizeof(saClnt);
            nchar=recvfrom(pView ->m_sock,msg,1024,0, 
    (PSOCKADDR) &saClnt, &saClntLen);
            if(nchar<0)
            {     pView ->m_data[pView ->count + +] +
                 =“Error in recvfrom\n";
            pView ->InvalidateRect(NULL);
            }
            else
            {switch(msg[0])
            {
            case  ‘A':
            wsprintf(msg,“A:Client from %s attached\n",
                   inet_ntoa(saClnt.sin_addr));
            pView ->m_data[pView ->count + +]=msg;
            pView ->flag=TRUE;
            pView ->InvalidateRect(NULL);
            pView ->Isconnect=TRUE;
            pView ->saClnt=saClnt;
            pView ->saClntLen=saClntLen;
            sendto(pView ->m_sock,msg,1024,0,(PSOCKADDR) 
            &saClnt,saClntLen);
            break;
                      
            case ‘D':
            wsprintf(msg,“D: Client form %s detached\n",
                    inet_ntoa(saClnt.sin_addr));
            pView ->m_data[pView ->count + +]=msg;
            pView ->flag=TRUE;
            pView ->InvalidateRect(NULL);
            pView ->Isconnect=FALSE;
           sendto(pView ->m_sock,msg,1024,0,(PSOCKADDR) 
           &saClnt,saClntLen);
            break;
    
            case ‘R':
            saClntLen=sizeof(saClnt);
            pView ->m_data[pView ->count + +]=msg;
            pView ->flag=TRUE;
            pView ->InvalidateRect(NULL);
            break;
    
            default:
            break;
            }
            }
                
          }
          return(0);
    }
    
  6. 在 程 序 菜 单 项 中 添 加“ 本 机IP 地 址":
        void CServerView::OnIp() 
    {int WSAReturn;
     WSAReturn=WSAStartup( 0x0101, &WSAData );
     if( WSAReturn == 0 ){
     gethostname( Hostname, 260 );
     struct hostent *pHostEnt;
     pHostEnt = gethostbyname( Hostname);
     if( pHostEnt != NULL ){
     wsprintf( Hostaddress, “ %d. %d. %d. %d",
    ( pHostEnt ->h_addr_list[0][0] & 0x00ff ),
    ( pHostEnt ->h_addr_list[0][1] & 0x00ff ),
    ( pHostEnt ->h_addr_list[0][2] & 0x00ff ),
    ( pHostEnt ->h_addr_list[0][3] & 0x00ff ) );
        CString out;      
        out.Format(Hostaddress);
        AfxMessageBox(out);
        }
          }
    }
    
  7. 在 程 序 菜 单 中 添 加“ 发 送 消 息":
        void CServerView::OnSendmessage() 
    {// TODO: Add your command handler code here
          char msg[2000];
          Csend Sendmessage;
          if(Sendmessage.DoModal()==IDOK 
        & &!Sendmessage.m_Message.IsEmpty())
        { wsprintf(msg,“R: " +Sendmessage.m_Message);
        sendto(m_sock,msg,1024,0,(PSOCKADDR) 
          &saClnt,saClntLen);
        m_data[count + +]=Sendmessage.m_Message;
        flag=TRUE;
        InvalidateRect(NULL);
        }
    }
    
  8. 为 发 送 消 息 项 添 加 一 个 对 话 框 的 类, 名 为send, 有 一 个 文 本 框, 用 来 发 送 消 息, 并 为 文 本 框 添 加CString m_Message 变 量, 在ServerView.cpp 中 添 加 #include “send.h"
  9. 为 发 送 消 息 项 添 加 一 个 判 断 函 数:
         void CServerView::OnUpdateSendmessage(CCmdUI * 
    pCmdUI) 
    {// TODO: Add your command update UI handler code here
          pCmdUI ->Enable(FALSE);
          if(Isconnect)
          pCmdUI ->Enable(TRUE);
    }
    
  10. 再 窗 口 显 示 消 息:
          void CServerView::OnDraw(CDC * pDC)
    {     if(flag)
          {sizeTotal.cy +=20;
           for(int j=65;j
    TextOut(10,y,m_data[i]);
                y +=20;}
          // TODO: add draw code for native data here
    }
    
  11. 在Project 中 点 击Settings 中 选 择Link 项 添 加wsock32.lib。

----最 后 编 译 程 序, 就 可 以 得 到Server.exe 程 序。

二、 客 户 机 程 序

  1. 创 建 一 个 名 为“client" 的 项 目, 单 文 档 界 面。
  2. 在clientview.h 中 加 入 代 码:
                #include “winsock.h"
        添 加 变 量:
                CString m_data[1000];
                HANDLE      m_hListenThread;
                SOCKET      m_sock;
                SOCKADDR_IN m_saSrvr;
                BOOL  Isconnect;
                int   count;
                CSize       sizeTotal;
                BOOL  flag;
    
  3. 在 构 造 函 数 中 初 始 化 变 量:
          CClientView::CClientView()
    {     // TODO: add construction code here
          Isconnect=FALSE;
          sizeTotal.cy=350;
          sizeTotal.cx=300;
          flag=FALSE;
    }
    
  4. 在 析 构 函 数 中 完 成 清 除 操 作, 代 码 如 上。
  5. 在 菜 单 中 添 加“ 拨 号" 项:
          void CClientView::OnDial() 
    {// TODO: Add your command handler code here
          count=5;
          if(m_bInitialized)
          {     AfxMessageBox(“Already dialing");
                return;}
          Cdial dial;
        if(dial.DoModal()==IDOK 
        & &!dial.m_HostAddress.IsEmpty())
          {m_saSrvr.sin_family=AF_INET;
           m_saSrvr.sin_addr.S_un.S_addr=htonl
    (INADDR_ANY);
           m_saSrvr.sin_addr.S_un.S_addr=inet_addr
    (dial.m_HostAddress);
           m_saSrvr.sin_port=htons(5050);
           int status;
           WSADATA wsaData;
           m_data[0]=“initializing Windows Sockets DLL....";
           if((status=WSAStartup(0x0101, &wsaData))==0)
          {     m_data[0] +=“Succeeded";
                m_bInitialized=TRUE;}
          else
          {     m_bInitialized=FALSE;}
          m_sock=socket(AF_INET,SOCK_DGRAM,0);
          m_data[1]=“Creating socket....";
          if(m_sock==INVALID_SOCKET)
          {     m_data[1] +=“Failed";}
          m_data[1] +=“Succeeded";
          m_data[2]=“Binding socket....";
          sockaddr_in sa;
          sa.sin_family=AF_INET;
          sa.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
          sa.sin_port=htons(0);
          if(bind(m_sock,(PSOCKADDR) 
         &sa,sizeof(sa))==SOCKET_ERROR)
          {     m_data[2] +=“Failed";
                closesocket(m_sock);}
          m_data[2] +=“Succeeded";
          m_data[3]=“Creating listener thread....";
          unsigned long idThread;
          m_hListenThread=CreateThread(NULL 0,
    (LPTHREAD_START_ROUTINE)Listen,
    (void *)this,0, &idThread);
          if(m_hListenThread)
          {     m_data[3] +=“Succeeded";
                m_data[4] +=“Waiting....";}
          else
          m_data[4] +=“Failed";
          InvalidateRect(NULL);
          }
    }
    
  6. 添 加 一 个 拨 号 对 话 框, 名 为dial, 有 一 个 文 本 框 用 来 写IP 地 址. 并 在clientview.cpp 中 添 加 代 码:
          #include dial.h
    
  7. 在 拨 号 项 添 加 一 个 判 断 函 数:
        void CClientView::OnUpdateDial(CCmdUI * 
    pCmdUI) 
    {// TODO: Add your command update UI handler code here
          pCmdUI ->Enable(TRUE);
          if(Isconnect)
          pCmdUI ->Enable(FALSE);
    }
    
  8. 添 加 接 收 与 发 送 消 息 的 线 程:
          long WINAPI Listen(CClientView *pView)
    {     char msg[2000];
          pView ->m_data[5]=“Sending ATTACH command";
          pView ->InvalidateRect(NULL);
          wsprintf(msg,“A: ");
         sendto(pView ->m_sock,msg,1024,0,(PSOCKADDR)
         &pView ->m_saSrvr,sizeof(pView ->m_saSrvr));
          int saSrvrLen ,nchar;
          while(1)
          {saSrvrLen=sizeof(pView ->m_saSrvr);
          nchar=recvfrom(pView ->m_sock,msg,1024,0,
       (PSOCKADDR) &pView ->m_saSrvr, &saSrvrLen);
          if(nchar<0)
         {    pView ->m_data[pView ->count + +]=
                 “Error in recvform";
          pView ->InvalidateRect(NULL);}
          else
         { pView ->m_data[pView ->count + +]=msg;
                      pView ->Isconnect=TRUE;
                      pView ->flag=TRUE;
                      pView ->InvalidateRect(NULL);
                }
          }
          return(0);
    }
    
  9. 同 主 程 序 一 样 做 一 个 发 送 消 息 项, 代 码 如 上。
  10. 显 示 程 序 也 与 主 程 序 一 样, 代 码 如 上。
  11. 在Project 中 点 击Settings 中 选 择Link 项 添 加wsock32.lib。
  12. 编 译 程 序 便 可 得 到client.exe 程 序。

----server.exe 和 client.exe 做 完 后, 就 可 以 在 具 有 TCP/IP 协 议 下 的 网 络 中 执 行。