VC:服务器与客户机互传消息 一、 服 务 器 程 序 创 建 一 个 名 为“server" 的 项 目, 单 文 档 界 面。 在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;// 是 否 连 接 在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"; } 在 析 构 函 数 中 完 成 必 需 的 清 除 操 作: CServerView:: ~CServerView() { if(m_bInitialized) WSACleanup(); closesocket(m_sock); if(m_hListenThread) ::TerminateThread(m_hListenThread,0); } 定 义 接 收 和 处 理 消 息 的 线 程: 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 recvfromn"; pView ->InvalidateRect(NULL); } else {switch(msg[0]) { case ‘A': wsprintf(msg,“A:Client from %s attachedn", 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 detachedn", 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); } 在 程 序 菜 单 项 中 添 加“ 本 机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);    } } } 在 程 序 菜 单 中 添 加“ 发 送 消 息":    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);    } } 为 发 送 消 息 项 添 加 一 个 对 话 框 的 类, 名 为send, 有 一 个 文 本 框, 用 来 发 送 消 息, 并 为 文 本 框 添 加CString m_Message 变 量, 在 ServerView.cpp 中 添 加 #include “send.h" 为 发 送 消 息 项 添 加 一 个 判 断 函 数: void CServerView::OnUpdateSendmessage(CCmdUI * pCmdUI) {// TODO: Add your command update UI handler code here pCmdUI ->Enable(FALSE); if(Isconnect) pCmdUI ->Enable(TRUE); } 再 窗 口 显 示 消 息: void CServerView::OnDraw(CDC * pDC) { if(flag) {sizeTotal.cy +=20; for(int j=65;jTextOut(10,y,m_data[i]); y +=20;} // TODO: add draw code for native data here } 在Project 中 点 击Settings 中 选 择Link 项 添 加wsock32.lib。 ----最 后 编 译 程 序, 就 可 以 得 到Server.exe 程 序。 二、 客 户 机 程 序 创 建 一 个 名 为“client" 的 项 目, 单 文 档 界 面。 在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; 在 构 造 函 数 中 初 始 化 变 量: CClientView::CClientView() { // TODO: add construction code here Isconnect=FALSE; sizeTotal.cy=350; sizeTotal.cx=300; flag=FALSE; } 在 析 构 函 数 中 完 成 清 除 操 作, 代 码 如 上。 在 菜 单 中 添 加“ 拨 号" 项: 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); } } 添 加 一 个 拨 号 对 话 框, 名 为dial, 有 一 个 文 本 框 用 来 写IP 地 址. 并 在clientview.cpp 中 添 加 代 码: #include dial.h 在 拨 号 项 添 加 一 个 判 断 函 数: void CClientView::OnUpdateDial(CCmdUI * pCmdUI) {// TODO: Add your command update UI handler code here pCmdUI ->Enable(TRUE); if(Isconnect) pCmdUI ->Enable(FALSE); } 添 加 接 收 与 发 送 消 息 的 线 程: 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); } 同 主 程 序 一 样 做 一 个 发 送 消 息 项, 代 码 如 上。 显 示 程 序 也 与 主 程 序 一 样, 代 码 如 上。 在Project 中 点 击Settings 中 选 择Link 项 添 加wsock32.lib。 编 译 程 序 便 可 得 到client.exe 程 序。 ----server.exe 和 client.exe 做 完 后, 就 可 以 在 具 有 TCP/IP 协 议 下 的 网 络 中 执 行。