用vc6.0编服务器与客户机互相传送消息的程序
---- 南京理工大学 朱晓华
---- 网络编程已经成为一种时髦,以TCP/IP协议的网络更为流行.自己编一个服务器与客户机互相传送消息的程序,以便增加自己网络编程的经验.下面我就介绍一下我编的程序.
---- 首先介绍服务器程序:
---- 1.创建一个名为"server"的项目,单文档界面.
---- 2.在serverview.h中加入代码:
#include "winsock.h" 添加变量: CSize sizeTotal;//控制滚动条 intcount;//信息条数 CString m_data[1000];//信息存放 char Hostname[260]; char Hostaddress[20];//主机IP地址 SOCKET m_sock; HANDLE m_hListenThread;//线程 BOOL m_bInitialized;//是否初始化 WSADATAWSAData; 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 *) this,0,&idThread); 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]=""; intnchar; 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;jTextOut(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; BOOLIsconnect; int count; CSize sizeTotal; BOOLflag;
---- 3.在构造函数中初始化变量:
CClientView::CClientView() { // TODO: add construction code here Isconnect=FALSE; sizeTotal.cy=350; sizeTotal.cx=300; flag=FALSE; }
---- 4.在析构函数中完成清除操作:
CClientView::~CClientView() {if(m_bInitialized) WSACleanup(); closesocket(m_sock); if(m_hListenThread) ::TerminateThread(m_hListenThread,0); }
---- 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协议下的网络中执行. 通过上面的例子,你可以很快了解vc++网络编程的优点,你还可以添加其它功能项,在这我就不多加叙述了.希望我的程序能起到抛砖引玉的目的,让我们都能编出好的网络程序.