C++之WSAAsyncSelect模型实例
本文实例讲述了C++中WSAAsyncSelect模型的用法。分享给大家供大家参考。具体实现方法如下:
TCPServer.cpp源文件如下:
#include"TCPServer.h" #include"resource.h" #defineWM_SOCKETWM_USER+1 CMyApptheApp; BOOLCMyApp::InitInstance() { //初始化套接字 WSADATAwsaData; WORDwVersionRequested=MAKEWORD(2,0); ::WSAStartup(wVersionRequested,&wsaData); //显示对话框 CMainDialogdlg; m_pMainWnd=&dlg; dlg.DoModal(); //释放套接字 ::WSACleanup(); returnFALSE; } //CMainDialog CMainDialog::CMainDialog(CWnd*pParentWnd):CDialog(IDD_MAINDIALOG,pParentWnd) { } BEGIN_MESSAGE_MAP(CMainDialog,CDialog) ON_BN_CLICKED(IDC_START,OnStart) ON_BN_CLICKED(IDC_CLEAR,OnClear) ON_MESSAGE(WM_SOCKET,OnSocket) END_MESSAGE_MAP() voidCMainDialog::OnCancel() { this->CloseAllSocket(); CDialog::OnCancel(); } BOOLCMainDialog::OnInitDialog() { CDialog::OnInitDialog(); //设置图标 SetIcon(theApp.LoadIconA(IDI_MAIN),FALSE); //创建状态栏并设置其属性 m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP,CRect(0,0,0,0),this,101); m_bar.SetBkColor(RGB(0xa6,0xca,0xfa)); intarWidth[]={200,-1}; m_bar.SetParts(2,arWidth); m_bar.SetText("windows程序设计",1,0); m_bar.SetText("空闲",0,0); //关联列表控件 m_listInfo.SubclassDlgItem(IDC_LIST,this); //初始化套接字和连接列表 m_socket=INVALID_SOCKET; m_nClient=0; //取得本机IP,在状态栏中显示 charszHostName[MAX_PATH]={0}; ::gethostname(szHostName,MAX_PATH); hostent*pHost=gethostbyname(szHostName); if(pHost!=NULL) { CStringstrIP; in_addr*addr=(in_addr*)*pHost->h_addr_list; strIP.Format("本机IP:%s",inet_ntoa(addr[0])); m_bar.SetText(strIP,0,0); } returnTRUE; } BOOLCMainDialog::CreateAndListen(intnPort) { if(m_socket==INVALID_SOCKET) { ::closesocket(m_socket); } //创建套接字 m_socket=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(m_socket==INVALID_SOCKET) { returnFALSE; } //绑定端口 sockaddr_insin; sin.sin_family=AF_INET; sin.sin_port=htons(nPort); //sin.sin_addr.S_un.S_addr=INADDR_ANY; sin.sin_addr.s_addr=INADDR_ANY; intnErr=GetLastError(); if(::bind(m_socket,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR) { nErr=GetLastError(); returnFALSE; } ::WSAAsyncSelect(m_socket,m_hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE|FD_READ); //进入监听模式 ::listen(m_socket,5); returnTRUE; } BOOLCMainDialog::AddClient(SOCKETs) { if(m_nClient<MAX_SOCKET) { m_arClient[m_nClient++]=s; returnTRUE; } returnFALSE; } voidCMainDialog::RemoveClient(SOCKETs) { BOOLbFound=FALSE; inti; for(i=0;i<m_nClient;i++) { if(m_arClient[i]==s) { bFound=TRUE; break; } } //找到 if(bFound) { m_nClient--; for(intj=i;j<m_nClient;j++) { m_arClient[j]=m_arClient[j+1]; } } } voidCMainDialog::CloseAllSocket() { if(m_socket!=INVALID_SOCKET) { ::closesocket(m_socket); m_socket=INVALID_SOCKET; } for(inti=0;i<m_nClient;i++) { ::closesocket(m_arClient[i]); } m_nClient=0; } voidCMainDialog::OnStart() { if(m_socket==INVALID_SOCKET)//开启服务 { CStringstrPort; GetDlgItem(IDC_PORT)->GetWindowText(strPort); intnPort=atoi(strPort); if(nPort<1||nPort>65535) { MessageBox("porterror"); return; } //创建套接字 if(!this->CreateAndListen(nPort)) { MessageBox("createsocketerror"); return; } //设置控件状态 GetDlgItem(IDC_START)->SetWindowTextA("停止服务"); m_bar.SetText("正在监听...",0,0); GetDlgItem(IDC_PORT)->EnableWindow(FALSE); } else//关闭服务 { CloseAllSocket(); GetDlgItem(IDC_START)->SetWindowTextA("开启服务"); m_bar.SetText("空闲",0,0); GetDlgItem(IDC_PORT)->EnableWindow(TRUE); } return; } voidCMainDialog::OnClear() { m_listInfo.ResetContent(); return; } longCMainDialog::OnSocket(WPARAMwParam,LPARAMlParam) { //得到句柄 SOCKETs=wParam; //查看是否出错 if(WSAGETSELECTERROR(lParam)) { RemoveClient(s); ::closesocket(s); return0; } //处理发生的事件 switch(WSAGETSELECTEVENT(lParam)) { caseFD_ACCEPT://监听到有套接字中有连接进入 { MessageBox("server:accept"); if(m_nClient<MAX_SOCKET) { SOCKETclient=::accept(s,NULL,NULL); this->AddClient(client); } else { MessageBox("toomanyconnection"); } } break; caseFD_CLOSE: { MessageBox("server:close"); RemoveClient(s); closesocket(s); } break; caseFD_READ://接收到对方发来的数据包 { MessageBox("server:read"); //得到对方的地址 sockaddr_insockAddr; memset(&sockAddr,0,sizeof(sockAddr)); intnSockAddrLength=sizeof(sockAddr); ::getpeername(s,(sockaddr*)&sockAddr,&nSockAddrLength); intnPeerPort=ntohs(sockAddr.sin_port); CStringstrIP=inet_ntoa(sockAddr.sin_addr); //strIP //获得主机名称 DWORDdwIP=::inet_addr(strIP); hostent*pHost=::gethostbyaddr((LPSTR)&dwIP,4,AF_INET); charszHostName[256]={0}; strncpy(szHostName,pHost->h_name,256); //得到网络数据 charszContent[1024]={0}; ::recv(s,szContent,1024,0); //显示 CStringstrItem=CString(szHostName)+"["+strIP+"]:"+CString(szContent); m_listInfo.InsertString(0,strItem); } break; } return0; }
TCPServer.h头文件如下:
#include<afxwin.h> #include<afxext.h> //CStatusBar #include<WinSock2.h> #include<afxcmn.h> #pragmacomment(lib,"WS2_32.lib") #define MAX_SOCKET56//最大客户量 classCMyApp:public CWinApp { public: BOOLInitInstance(); }; //CMainDialog classCMainDialog:publicCDialog { public: CMainDialog(CWnd*pParentWnd=NULL); protected: virtualBOOLOnInitDialog(); virtualvoidOnCancel(); //开启或停止服务 afx_msgvoidOnStart(); afx_msgvoidOnClear(); afx_msglongOnSocket(WPARAMwParam,LPARAMlParam); BOOLCreateAndListen(intnPort); //向客户连接列表中加一个客户 BOOLAddClient(SOCKETs); //从客户连接列表中移除一个客户 voidRemoveClient(SOCKETs); //关闭所有连接 voidCloseAllSocket(); protected: SOCKETm_socket; //两个子窗口控件 CListBoxm_listInfo; CStatusBarCtrlm_bar; //客户连接列表 SOCKETm_arClient[MAX_SOCKET];//套接字列表 intm_nClient;//上述数组的大小 DECLARE_MESSAGE_MAP() };
TCPClient.cpp源文件如下:
#include"TCPClient.h" #include"resource.h" #defineWM_SOCKETWM_USER+1 CMyApptheApp; BOOLCMyApp::InitInstance() { //初始化套接字 WSADATAwsaData; WORDwVersionRequested=MAKEWORD(2,0); ::WSAStartup(wVersionRequested,&wsaData); //显示对话框 CMainDialogdlg; m_pMainWnd=&dlg; dlg.DoModal(); //释放套接字 ::WSACleanup(); returnFALSE; } //CMainDialog CMainDialog::CMainDialog(CWnd*pParentWnd):CDialog(IDD_MAINDIALOG,pParentWnd) { } BEGIN_MESSAGE_MAP(CMainDialog,CDialog) ON_BN_CLICKED(IDC_CONNECT,OnConnect) ON_BN_CLICKED(IDC_SEND,OnSend) ON_MESSAGE(WM_SOCKET,OnSocket) END_MESSAGE_MAP() voidCMainDialog::OnCancel() { CDialog::OnCancel(); } BOOLCMainDialog::OnInitDialog() { CDialog::OnInitDialog(); //设置图标 SetIcon(theApp.LoadIconA(IDI_MAIN),FALSE); //关联控件 m_edit_text.SubclassDlgItem(IDC_EDIT_CONTENT,this); //状态栏 m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP,CRect(0,0,0,0),this,NULL); intnWidth[]={100,-1}; m_bar.SetParts(2,nWidth); m_bar.SetText("windows程序设计",1,0); m_bar.SetText("空闲",0,0); GetDlgItem(IDC_ADDR)->SetWindowTextA("192.168.19.143"); GetDlgItem(IDC_PORT)->SetWindowTextA("9999"); // m_socket=INVALID_SOCKET; returnTRUE; } voidCMainDialog::AddStringToList(CStringstrText) { CStringstrContent; GetDlgItem(IDC_EDIT_CONTENT)->GetWindowText(strContent); GetDlgItem(IDC_EDIT_CONTENT)->SetWindowText(strContent+strText); } longCMainDialog::OnSocket(WPARAMwParam,LPARAMlParam) { SOCKET s=wParam; if(WSAGETSELECTERROR(lParam)) { ::closesocket(m_socket); m_socket=INVALID_SOCKET; return0; } switch(WSAGETSELECTEVENT(lParam)) { caseFD_READ: { MessageBox("client:read"); charszText[1024]={0}; ::recv(s,szText,1024,0); AddStringToList(CString(szText)+"\r\n"); } break; caseFD_CONNECT: { MessageBox("client:connect"); GetDlgItem(IDC_CONNECT)->SetWindowTextA("断开连接"); GetDlgItem(IDC_ADDR)->EnableWindow(FALSE); GetDlgItem(IDC_PORT)->EnableWindow(FALSE); GetDlgItem(IDC_TEXT)->EnableWindow(TRUE); GetDlgItem(IDC_SEND)->EnableWindow(TRUE); m_bar.SetText("已经连接到服务器",0,0); } break; caseFD_CLOSE: { MessageBox("client:close"); OnConnect(); } break; } return0; } BOOLCMainDialog::Connect(LPCTSTRpszRemoteAddr,u_shortnPort) { //创建套接字 m_socket=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(INVALID_SOCKET==m_socket) { returnFALSE; } ::WSAAsyncSelect(m_socket,m_hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE); ULONGuAddr=::inet_addr(pszRemoteAddr); if(uAddr==INADDR_NONE) { //不是IP地址,就认为是主机名称 //从主机名得到IP hostent*pHost=::gethostbyname(pszRemoteAddr); if(pHost==NULL) { ::closesocket(m_socket); m_socket=INVALID_SOCKET; returnFALSE; } uAddr=((structin_addr*)*(pHost->h_addr_list))->s_addr; } //填写服务器信息 sockaddr_inremote; remote.sin_family=AF_INET; remote.sin_addr.S_un.S_addr=uAddr; remote.sin_port=::htons(nPort); //连接 ::connect(m_socket,(sockaddr*)&remote,sizeof(sockaddr)); returnTRUE; } voidCMainDialog::OnConnect() { if(INVALID_SOCKET==m_socket)//连接服务器 { CStringstrAddr; GetDlgItem(IDC_ADDR)->GetWindowText(strAddr); if(strAddr.IsEmpty()) { MessageBox("theserversIPisempty"); return; } CStringstrPort; GetDlgItem(IDC_PORT)->GetWindowTextA(strPort); intnPort=atoi(strPort); if(nPort<1||nPort>65535) { MessageBox("porterror"); return; } if(Connect(strAddr,nPort)==FALSE) { MessageBox("connecttoserverserror..."); return; } //设置用户界面 GetDlgItem(IDC_CONNECT)->SetWindowText("取消"); m_bar.SetText("正在连接..",0,0); } else//断开服务器 { ::closesocket(m_socket); m_socket=INVALID_SOCKET; //设置用户界面 GetDlgItem(IDC_CONNECT)->SetWindowTextA("连接服务器"); m_bar.SetText("空闲",0,0); GetDlgItem(IDC_ADDR)->EnableWindow(TRUE); GetDlgItem(IDC_PORT)->EnableWindow(TRUE); GetDlgItem(IDC_SEND)->EnableWindow(FALSE); GetDlgItem(IDC_TEXT)->EnableWindow(FALSE); } //this->Connect(szAddr,) } voidCMainDialog::OnSend() { CStringstrSendContent; GetDlgItem(IDC_TEXT)->GetWindowTextA(strSendContent); ::send(m_socket,strSendContent,strSendContent.GetLength(),0); GetDlgItem(IDC_TEXT)->SetWindowTextA(""); }
TCPClient.h头文件如下:
#include<afxwin.h> #include<afxext.h> //CStatusBar #include<WinSock2.h> #include<afxcmn.h> #pragmacomment(lib,"WS2_32.lib") #define MAX_SOCKET56//最大客户量 classCMyApp:public CWinApp { public: BOOLInitInstance(); }; //CMainDialog classCMainDialog:publicCDialog { public: CMainDialog(CWnd*pParentWnd=NULL); protected: virtualBOOLOnInitDialog(); virtualvoidOnCancel(); ////开启或停止服务 //afx_msgvoidOnStart(); afx_msgvoidOnSend(); afx_msglongOnSocket(WPARAMwParam,LPARAMlParam); voidOnConnect(); BOOLConnect(LPCTSTRpszRemoteAddr,u_shortnPort); SOCKETm_socket; //控件 CStatusBarCtrlm_bar; CEditm_edit_text; voidAddStringToList(CStringstrText); //BOOLCreateAndListen(intnPort); ////向客户连接列表中加一个客户 //BOOLAddClient(SOCKETs); ////从客户连接列表中移除一个客户 //voidRemoveClient(SOCKETs); ////关闭所有连接 //voidCloseAllSocket(); DECLARE_MESSAGE_MAP() };
希望本文所述对大家的C++程序设计有所帮助。