首页 > 编程资源分享区 > C/C++源代码共享 > 服务器与客户机互传消息
2006
02-23

服务器与客户机互传消息

一、服务器程序


  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(0×0101, &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( 0×0101, &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;jTextOut(10,y,m_data);
      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(0×0101, &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 协议下的网络中执行。  


留下一个回复