上次的文章我给大家简单的介绍了一下WinSocket的使用方法,相信大家已经对它产生了一定的兴趣,接下来我会带领大家进入网络编程的世界,今天我会逐步的给大家讲解如何利用WinSocket实现一个网络聊天室。正如大多数聊天室一样,我们需要一个聊天服务器它可以和很多客户端进行通信,从而实现把来自不同的客户的聊天信息转交到所有其他的客户端。这样就形成一个采用C/S结构的可以多人同时在线的聊天室。今天我们就利用上次文章中的知识来实现它。(这里我们需要你有一些VC的MFC知识,最好可以会编一些简单的窗口程序,当然我也会尽可能的讲的具体一些。)
我们先来做一个客户端。
首先启动VC,利用MFC AppWizard[EXE]建立一个新的MFC程序,取名为ChatRoom,在MFC AppWizard Step 1的时候我们选择Dialog based,在Step 2时我们一定要选择上Windows Sockets选项,切记!切记!之后的几步我们就可以使用默认值了。
我们要做的客户端分为两个窗口,一个是登陆窗口,需要你输入一些登陆信息,另外就是聊天主窗口。如下图:
相信这两个窗口不难建立吧?其中那个聊天主窗口是程序生成的时候自己建立的,而那个登陆窗口是后添进去的,为了可以在主窗口出现之前启动先启动登陆窗口,我们需要在CChatRoomApp::InitInstance中更改代码。(其中我们为登陆窗口建立的类叫ConnectDlg)
BOOL CChatRoomApp::InitInstance() { if (!AfxSocketInit()) { AfxMessageBox(IDP_SOCKETS_INIT_FAILED); return FALSE; } AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif CClientSocket *tmpSocket; CConnectDlg *cdlg; CChatRoomDlg *dlg; int nResponse,cnResponse=IDOK,endFlage=1; tmpSocket=new CClientSocket; cdlg=new CConnectDlg(tmpSocket); cnResponse=cdlg->DoModal(); if (cnResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel delete tmpSocket; delete cdlg; return FALSE; } else { delete cdlg; } dlg=new CChatRoomDlg(tmpSocket); tmpSocket->SetDlg(dlg); nResponse = dlg->DoModal(); m_pMainWnd = dlg; if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK if (tmpSocket) tmpSocket->Close(); tmpSocket->myDlg=NULL; delete tmpSocket; tmpSocket=NULL; } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel if (tmpSocket) tmpSocket->Close(); delete tmpSocket; } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application@#s message pump. return FALSE; } |
下面是登陆窗口中点击登陆按钮时的处理网络连接的函数:(其中m_IDC_EDIT_NIKENAME、m_IDC_EDIT_ADDRESS分别对应两个输入框)
void CConnectDlg::OnOK() { // TODO: Add extra validation here UpdateData(TRUE); char *nikename,*address; int n; if (!myServerSocket->Create()) { myServerSocket->Close(); AfxMessageBox("网络创建错误!!"); return; } n=m_IDC_EDIT_ADDRESS.GetLength(); address=new char(n+1); sprintf(address,"%s",m_IDC_EDIT_ADDRESS.GetBuffer(n)); address[n]=0; n=m_IDC_EDIT_NIKENAME.GetLength(); nikename=new char(n+1); sprintf(nikename,"%s",m_IDC_EDIT_NIKENAME.GetBuffer(n)); nikename[n]=0; if (!myServerSocket->Connect(address,6767)) { myServerSocket->Close(); AfxMessageBox("网络连接错误,请检查服务器地址。"); return; } myServerSocket->NikeName=nikename; CDialog::OnOK(); } |
接下来就是住对话框里面的发送按钮的函数:(其中m_IDC_EDIT_MESSAGE是发送信息框)
void CChatRoomDlg::OnButtonSend() { // TODO: Add your control notification handler code here int n; char message[1000]; UpdateData(TRUE); m_IDC_EDIT_MESSAGE=myServerSocket->NikeName+": "+m_IDC_EDIT_MESSAGE; n=m_IDC_EDIT_MESSAGE.GetLength(); sprintf(message,"%s",m_IDC_EDIT_MESSAGE.GetBuffer(n)); message[n]=0; if (myServerSocket->Send(message,n+1)) { m_IDC_EDIT_MESSAGE=""; UpdateData(FALSE); } else { AfxMessageBox("网络传输错误!"); } } |
大家注意到了我有一个CClientSocket类,其中有一个很重要的成员函数,它实现了立即显示从服务器获得的聊天信息到聊天对话框中的功能。
void CClientSocket::OnReceive(int nErrorCode) { // TODO: Add your specialized code here and/or call the base class myDlg->GetMessage(); CSocket::OnReceive(nErrorCode); } |
它调用了主对话框的成员函数GetMessage来显示聊天信息。
BOOL CChatRoomDlg::GetMessage() { char buff[1000]; int count; count=myServerSocket->Receive(buff,1000); buff[count]=0; m_LIST_CHATBOX_CONTROL.AddString(buff); return true; } |
好了,这就是基本的客户端程序,他做得还不是很漂亮,你可以根据自己的喜好自行修改。我们下回将介绍服务器程序的制作,到那时你就可以拥有自己的聊天室了。