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++程序设计有所帮助。