Socket异步选择模型实例—聊天室

 

 

socket编程SERVER端

SOCKET编程Client端

 

利用这个模型,应用程序可在一个套接字上,接收以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);
}

完成效果

 



文章来自: 本站原创
Tags:
评论: 0 | 查看次数: 7515