WinSocket高级实现(聊天室的实现)(一)

发表于:2007-07-01来源:作者:点击数: 标签:
上次的文章我给大家简单的介绍了一下WinSocket的使用方法,相信大家已经对它产生了一定的兴趣,接下来我会带领大家进入 网络 编程的世界,今天我会逐步的给大家讲解如何利用WinSocket实现一个网络聊天室。正如大多数聊天室一样,我们需要一个聊天 服务器 它


  上次的文章我给大家简单的介绍了一下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;
}

好了,这就是基本的客户端程序,他做得还不是很漂亮,你可以根据自己的喜好自行修改。我们下回将介绍服务器程序的制作,到那时你就可以拥有自己的聊天室了。


原文转自:http://www.ltesting.net