Socket异步选择模型实例—聊天室
作者:admin 日期:2012-04-23
利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect()函数。
int WSAAsyncSelect(
SOCKET s, //要进行操作的SOCKET
HWND hWnd, //要绑写的窗口句柄(当事件发生后要接收消息的窗口)
unsigned int wMsg, //网络事件发生时的的消息响应
long lEvent //感兴趣的网络事件
);
核心程序代码:
服务器端
void CServerDlg::OnBtnStart()
{
UpdateData();
m_SrvSock=socket(AF_INET,SOCK_STREAM,0); //CServerDlg类成员变量:m_SrvSock
if(INVALID_SOCKET==m_SrvSock)
{
MessageBox("创建套接字失败!","错误");
return;
}
SOCKADDR_IN addr_Srv;
addr_Srv.sin_family=AF_INET;
addr_Srv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addr_Srv.sin_port=htons(m_Port);
int nerr;
nerr=bind(m_SrvSock,(SOCKADDR *)&addr_Srv,sizeof(SOCKADDR));
if(SOCKET_ERROR==nerr)
{
MessageBox("绑定套接字失败!","错误");
return;
}
nerr=WSAAsyncSelect(m_SrvSock,m_hWnd,WM_NETWORK,FD_READ | FD_ACCEPT | FD_CLOSE);
if(SOCKET_ERROR==nerr)
{
MessageBox("注册异步事件失败!","错误");
return;
}
listen(m_SrvSock,10);
GetDlgItem(IDC_BTN_START)->EnableWindow(false);
GetDlgItem(IDC_BTN_STOP)->EnableWindow();
}
void CServerDlg::OnNetwork(WPARAM wParam,LPARAM lParam)
{
SOCKET CurSock=(SOCKET)wParam;
switch(LOWORD(lParam))
{
case FD_ACCEPT:
OnAccept(CurSock);
break;
case FD_READ:
OnRecv(CurSock);
break;
case FD_CLOSE:
OnClose(CurSock);
break;
default:
break;
}
}
void CServerDlg::OnAccept(SOCKET CurSock)
{
SOCKADDR_IN addr_Clt;
int len=sizeof(SOCKADDR);
m_CltSock=accept(CurSock,(SOCKADDR *)&addr_Clt,&len);
WSAAsyncSelect(m_CltSock,m_hWnd,WM_NETWORK,FD_READ | FD_WRITE | FD_CLOSE);
}
void CServerDlg::OnRecv(SOCKET CurSock)
{
char RecvBuf[100];
recv(CurSock,RecvBuf,100,0);
SOCKADDR_IN addr_Clt;
int len=sizeof(SOCKADDR);
getpeername(CurSock,(SOCKADDR *)&addr_Clt,&len);
m_List.InsertItem(m_nItem,inet_ntoa(addr_Clt.sin_addr));
m_List.SetItemText(m_nItem,1,RecvBuf);
CTime time=CTime::GetCurrentTime();
CString CurTime=time.Format("%H:%M:%S");
m_List.SetItemText(m_nItem,2,CurTime);
m_nItem++;
}
void CServerDlg::OnClose(SOCKET CurSock)
{
if(CurSock)
closesocket(CurSock);
}
void CServerDlg::OnBtnStop()
{
if(m_SrvSock)
closesocket(m_SrvSock);
GetDlgItem(IDC_BTN_START)->EnableWindow();
GetDlgItem(IDC_BTN_STOP)->EnableWindow(false);
}
void CServerDlg::OnBtnSend()
{
CString strSend;
GetDlgItemText(IDC_EDIT_SEND,strSend);
int nerr=send(m_CltSock,strSend,strSend.GetLength()+1,0);
if(SOCKET_ERROR==nerr)
{
MessageBox("发送数据失败!","错误");
}
SetDlgItemText(IDC_EDIT_SEND,"");
}
客户端
BOOL CClientDlg::InitSocket()
{
m_CltSock=socket(AF_INET,SOCK_STREAM,0);
if(INVALID_SOCKET==m_CltSock)
{
MessageBox("创建套接字失败!","错误");
return false;
}
SOCKADDR_IN addr_Srv;
addr_Srv.sin_family=AF_INET;
addr_Srv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addr_Srv.sin_port=htons(8800);
int nerr=connect(m_CltSock,(SOCKADDR *)&addr_Srv,sizeof(SOCKADDR));
if(SOCKET_ERROR==nerr)
{
MessageBox("连接服务器失败!","错误");
}
WSAAsyncSelect(m_CltSock,m_hWnd,WM_NETEVENT,FD_READ);
return true;
}
void CClientDlg::OnNetEvent(WPARAM wParam,LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_READ:
OnRecv();
break;
default:
break;
}
}
void CClientDlg::OnBtnSend()
{
CString strSend,strRecved;
GetDlgItemText(IDC_EDIT_SEND,strSend);
GetDlgItemText(IDC_EDIT_RECV,strRecved);
strRecved+="\r\n";
send(m_CltSock,strSend,strSend.GetLength()+1,0);
CString strTemp;
SOCKADDR_IN addr_Cnn;
int len=sizeof(SOCKADDR);
getpeername(m_CltSock,(SOCKADDR *)&addr_Cnn,&len);
strTemp.Format("%s说:%s",inet_ntoa(addr_Cnn.sin_addr),strSend);
strRecved+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,strRecved);
SetDlgItemText(IDC_EDIT_SEND,"");
}
void CClientDlg::OnRecv()
{
char RecvBuf[100],TempBuf[200];
CString strRecved;
GetDlgItemText(IDC_EDIT_RECV,strRecved);
strRecved+="\r\n";
recv(m_CltSock,RecvBuf,100,0);
SOCKADDR_IN addr_Cnn;
int len=sizeof(SOCKADDR);
getpeername(m_CltSock,(SOCKADDR *)&addr_Cnn,&len);
sprintf(TempBuf,"%s说:%s",inet_ntoa(addr_Cnn.sin_addr),RecvBuf);
strRecved+=TempBuf;
SetDlgItemText(IDC_EDIT_RECV,strRecved);
}
完成效果