服务器与客户机互传消息

一、 服 务 器 程 序

  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 协 议 下 的 网 络 中 执 行。