当前位置: 首页 > 工具软件 > XEIM > 使用案例 >

C++写的一个聊天室代码,用于XEIM开源即时通讯软件上的

宗政法
2023-12-01

// C++写的一个聊天室代码,用于XEIM开源即时通讯软件上的,欢迎大家一起交流。

// XEIM_ChatroomDlg.cpp : implementation file
// [即时通讯软件],[XEIM],[飞鸽传书]

#include "stdafx.h"
#include "xeim.h"
#include "xeimDlg.h"
#include "XEIM_ChatroomDlg.h"
#include "XEIM_Text.h"
#include "XEIM_Message.h"
#include "XEIM_ChatDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CXEIM_ChatroomDlg dialog


CXEIM_ChatroomDlg::CXEIM_ChatroomDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CXEIM_ChatroomDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CXEIM_ChatroomDlg)
  // NOTE: the ClassWizard will add member initialization here
 m_bServerRunning = FALSE;
 m_hServer = INVALID_HANDLE_VALUE;
 //}}AFX_DATA_INIT
 m_hIcon = AfxGetApp()->LoadIcon(IDI_ICONCHAT);
}

CXEIM_ChatroomDlg::CXEIM_ChatroomDlg(LPCTSTR lpszUID, CWnd* pParent/* = NULL*/)
{
 m_hIcon = AfxGetApp()->LoadIcon(IDI_ICONCHAT);
 m_bServerRunning = FALSE;
 m_hServer = INVALID_HANDLE_VALUE;
 CString strUID = lpszUID;
 if (! strUID.IsEmpty())
 {
  m_bServerRunning = TRUE;
  if (! m_client.xConnect(M()->T.GetContactIP(lpszUID), 9989))
  {
   MessageBox(m_client.m_strLastError);
   return;
  }
  else
  {
   DWORD dwTID;
   m_client.SetWnd(this);
   HANDLE hThread = CreateThread(NULL, 0, SockRecvProc, (LPVOID)&m_client, 0, & dwTID);
   if (NULL == hThread)
   {
    MessageBox("CreateThread(NULL, 0, CreateHTML_Proc, (LPVOID)m_client, 0, & dwTID) failed.");
    return;
   }
   m_mapClient.insert(pair<HANDLE, CXEIMSocket*>(hThread, &m_client));
  }
 }
}


void CXEIM_ChatroomDlg::AddRecvText(LPCTSTR lpszUser, LPCTSTR lpszData)
{
 CTime m_StartTime1 = CTime::GetCurrentTime();
 CString csStartTime;
 // 信息 发送者 和 发送时间
 csStartTime.Format(_T("%s - %s/r/n"), M()->T.GetContactDisplayName(lpszUser),
  m_StartTime1.Format(_T("%H:%M:%S")));

 //
 int iTotalTextLength = m_richMsg.GetWindowTextLength();
 m_richMsg.SetSel(iTotalTextLength, iTotalTextLength);
 m_richMsg.ReplaceSel(csStartTime);
 int iStartPos = iTotalTextLength;
 CHARFORMAT cf;
 cf.cbSize = sizeof(CHARFORMAT);
 cf.dwMask = CFM_COLOR | CFM_UNDERLINE | CFM_BOLD;
 cf.dwEffects = (unsigned long)~(CFE_AUTOCOLOR | CFE_UNDERLINE | CFE_BOLD);
 cf.crTextColor = RGB(0, 128, 0);
 int iEndPos = m_richMsg.GetWindowTextLength();
 m_richMsg.SetSel(iStartPos, iEndPos);
 m_richMsg.SetSelectionCharFormat(cf);
 m_richMsg.SetSel(iEndPos, iEndPos);
 CString str = lpszData;

 int nIdx = 0;
 while (nIdx != -1)
 {
  nIdx = str.Find('/n', nIdx+1);
  str.Insert(nIdx+1, "  ");
 }
 str += "/r/n";

 m_richMsg.ReplaceSel(str);
 m_richMsg.SetSel(iEndPos, m_richMsg.GetWindowTextLength());
 cf.crTextColor = RGB(0, 0, 0);
 m_richMsg.SetSelectionCharFormat(cf);
 m_richMsg.PostMessage(WM_VSCROLL, SB_BOTTOM,0);

/* m_editAllMessage += lpszUser;
 m_editAllMessage += "/r/n";
 m_editAllMessage += lpszData;
 UpdateData(FALSE);
 AfxMessageBox(lpszData);*/
}

void CXEIM_ChatroomDlg::OnAcceptClose()
{
// AfxMessageBox("asdf");
}

void CXEIM_ChatroomDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
{
 CXEIMSocket *pclient = (CXEIMSocket*)lParam;
 CXEIMData *pData = (CXEIMData*)wParam;

// AfxMessageBox(pData->GetData());
 if (pData->GetMessage() == 2)
 {
  CString strData = pData->GetData();
  UINT nLeft = strData.Find("|");
  CString strUID = strData.Left(nLeft);
  CString strText = strData.Right(strData.GetLength()-nLeft-1);
  AddRecvText(strUID, strText);

  if (m_bServerRunning) {

   map<HANDLE, CXEIMSocket*>::iterator _beg=m_mapClient.begin(),
    _end=m_mapClient.end();

   for (; _beg != _end; _beg++)
   {
    _beg->second->xSend(pData->GetData(), pData->GetDataLength());
   }
  }
 }
 else if (pData->GetMessage() == 1)
 {
  CString strData = pData->GetData();
  CString strRight = strData;
  UINT nIdx = strData.Find("|");
  while (-1 != nIdx)
  {
   CString strUser = strRight.Left(nIdx);
   m_listboxUser.AddString(strUser);
   CString strk;
   strk.Format("%s - %d,%d",strData, nIdx, strData.GetLength());
   strRight = strRight.Right(strRight.GetLength()-nIdx-1);
   nIdx = strRight.Find("|");
  }
 }

 delete pData;
}

void CXEIM_ChatroomDlg::OnNewClient(WPARAM wParam, LPARAM lParam)
{
 CXEIMSocket *pClient = new CXEIMSocket((SOCKET)wParam, (CWnd*)lParam);

 DWORD dwTID;
 HANDLE hThread = CreateThread(NULL, 0, SockRecvProc, (LPVOID)pClient, 0, & dwTID);
 if (NULL == hThread)
 {
  MessageBox("CreateThread(NULL, 0, CreateHTML_Proc, (LPVOID)this, 0, & dwTID) failed.");
  return;
 }
 m_mapClient.insert(pair<HANDLE, CXEIMSocket*>(hThread, pClient));

 CString strUsers;
 int nCount = m_listboxUser.GetCount(); // 得到项目总数
 for(int i=0; i<nCount; ++ i)
 {
  CString strText;
  m_listboxUser.GetText(i, strText);
  strUsers += strText;
  strUsers += "|";
 }
 pClient->xSend1(strUsers, strUsers.GetLength()+1);
// MessageBox(pClient->GetHostAddress());
}

void CXEIM_ChatroomDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CXEIM_ChatroomDlg)
 DDX_Control(pDX, IDC_RICHEDIT1, m_richMsg);
 DDX_Control(pDX, IDC_LIST1, m_listboxUser);
 //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CXEIM_ChatroomDlg, CDialog)
 //{{AFX_MSG_MAP(CXEIM_ChatroomDlg)
 ON_MESSAGE(WM_SERVER_CREATED, OnServerCreated)
 ON_MESSAGE(WM_ACCEPT_CLOSE, OnAcceptClose)
 ON_MESSAGE(WM_NEW_CLIENT, OnNewClient)
 ON_MESSAGE(WM_RECV_DATA, OnRecvData)
 ON_BN_CLICKED(IDC_SEND, OnSend)
 ON_MESSAGE(XM_EMDBLCLICKTREE, XDoubleClickUserList)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CXEIM_ChatroomDlg message handlers

void CXEIM_ChatroomDlg::OnOK()
{
 // TODO: Add extra validation here
 CDialog::OnOK();
}

void CXEIM_ChatroomDlg::OnCancel()
{
 // TODO: Add extra cleanup here
 
 CDialog::OnCancel();
}

void CXEIM_ChatroomDlg::OnSend()
{
 // TODO: Add your control notification handler code here
/* UpdateData();
 if (m_editSend.IsEmpty())
 {
  AfxMessageBox("请输入要发送的消息");
  return;
 }

 if (! m_bServerRunning) { // 客户端
  m_client.xSend(m_editSend, m_editSend.GetLength()+1);
 }
 else // 服务端
 {
  map<HANDLE, CXEIMSocket*>::iterator _beg=m_mapClient.begin(),
   _end=m_mapClient.end();
  for (; _beg != _end; _beg++)
  {
   _beg->second->xSend(m_editSend, m_editSend.GetLength()+1);
  }
  AddRecvText("Server", m_editSend);
 }

 m_editSend = "";
 UpdateData(FALSE);*/
 CString str;
 GetDlgItemText(IDC_RICHEDIT2, str);
 if(str.IsEmpty())
 {
  MessageBox("请输入消息内容!");
  return;
 }
 if (str.GetLength() > 1024 - 100)
 {
  CString str2;
  str2.Format(_T("你所发的信息太长,请分几次发送,最大 1024 个字符。"), str.GetLength());
  MessageBox(str2, _T("警告"), MB_ICONINFORMATION);
  return;
 }

 CString strSend;
 strSend.Format(_T("%s|%s"), M()->T.GetLocalUID(), str);

 if (! m_bServerRunning)
 {
  m_client.xSend(strSend, strSend.GetLength()+1);
 }
 else
 {
  map<HANDLE, CXEIMSocket*>::iterator
   _beg=m_mapClient.begin(),
   _end=m_mapClient.end();

  for (; _beg != _end; _beg++)
  {
   _beg->second->xSend(strSend, strSend.GetLength()+1);
  }

  AddRecvText(M()->T.GetLocalUID(), str);
 }

 SetDlgItemText(IDC_RICHEDIT2, "");
// m_client.xSend("33",3);
}

void CXEIM_ChatroomDlg::OnServerCreated(WPARAM wParam, LPARAM lParam)
{
 XEIM _p = M();

 CString strFileString;
 strFileString.Format(_T("%s|%s"), XEIM_CHATROOM, m_strChatroomName);

/* map<HTREEITEM, XEIM_User*>::iterator imap
  = _p->m_chatroomUsers.begin(),
  _end = _p->m_chatroomUsers.end();

 // 读取聊天室成员
 for (; imap!=_end; ++imap) {

  CXEIM_Text xText(imap->second->GetUID(), strFileString);
  // 获取用户联系人
  XEIM_Message toSend("forward",xText.GetBuffer());
 // AfxMessageBox(toSend.GetData());
  if(! _p->m_iocp.BuildPackageAndSend(_p->m_serverSocket,Job_UserData,toSend.GetBuffer()))
  {
   AfxMessageBox("Send not successfull.!");
  }

 // int nIndex = m_listboxUser.AddString(imap->second->GetDisplayName());
 // m_listboxUser.SetItemData(nIndex, imap->first);
 }*/
}

BOOL CXEIM_ChatroomDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 
 // Set the icon for this dialog.  The framework does this automatically
 //  when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE);   // Set big icon
 SetIcon(m_hIcon, FALSE);  // Set small icon

 // TODO: Add extra initialization here

 // 设置聊天室名称
 CString strRoomname;
 strRoomname.Format(_T("%s - 聊天室"), m_strChatroomName);
 SetWindowText(strRoomname);

 // 创建 聊天室服务器 线程
/* if (! m_bServerRunning)
 {
  // 聊天是首先要有自己
  CString strSelfName = M()->GetLocalDisplayName();
  strSelfName += _T("(主机)");
  int nIndex = m_listboxUser.AddString(strSelfName);
  m_listboxUser.SetItemData(nIndex, 0);

  m_bServerRunning = TRUE;

  DWORD dwTID;
  m_hServer = CreateThread(NULL, 0, ServerThreadProc, (LPVOID)this, 0, & dwTID);
  if (NULL == m_hServer)
  {
   AfxMessageBox("CreateThread(NULL, 0, CreateHTML_Proc, (LPVOID)this, 0, & dwTID) failed.");
   return TRUE;
  }

  map<SOCKET, XEIM_User*>::iterator imap
  = M()->m_chatroomUsers.begin(),
  _end = M()->m_chatroomUsers.end();

  // 读取聊天室成员
  for (; imap!=_end; ++imap) {
   int nIndex = m_listboxUser.AddString(imap->second->GetDisplayName());
   m_listboxUser.SetItemData(nIndex, imap->first);
  }
 }
 else
 {
  m_bServerRunning = ! m_bServerRunning;
 }
*/
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}

 

DWORD CALLBACK CXEIM_ChatroomDlg::SockRecvProc(LPVOID lParam)
{
 CXEIMSocket *pclient = (CXEIMSocket*)lParam;
 CXEIM_ChatroomDlg *pDlg = (CXEIM_ChatroomDlg*)pclient->GetWnd();

// ::MessageBox(NULL,"","",MB_OK);
 while(1)
 {
  UINT nLen = 0;
  char * buf = pclient->xRecv(nLen);
  if (nLen > 0)
  {
   CXEIMData *pData = new CXEIMData(buf, nLen);
   if (pDlg)
    pDlg->PostMessage(WM_RECV_DATA, (WPARAM)pData, (LPARAM)pclient);
  }
  delete buf;
 }

 pclient->xShutdown(SD_BOTH);
 pclient->xCloseSocket();

 return -1;
}

DWORD CALLBACK CXEIM_ChatroomDlg::ServerThreadProc(LPVOID lParam)
{
 CXEIM_ChatroomDlg *pDlg = (CXEIM_ChatroomDlg*)lParam;

    //最好不要使用aSocket.Create创建,因为容易会出现10048错误
 pDlg->m_svrSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == pDlg->m_svrSocket)
    {
        char szError[256] = {0};
        sprintf(szError, "Create Faild: %d", WSAGetLastError());
        AfxMessageBox(szError);
        return -1;
    }

    BOOL bOptVal = TRUE;
    int bOptLen = sizeof(BOOL);
    //设置Socket的选项, 解决10048错误必须的步骤
 setsockopt(pDlg->m_svrSocket, SOL_SOCKET, SO_REUSEADDR, (LPSTR)&bOptVal, bOptLen);

   // pDlg->m_svrSocket.SetSockOpt(SO_REUSEADDR, (void *)&bOptVal, bOptLen, SOL_SOCKET);
 SOCKADDR_IN local;
 memset(&local, 0, sizeof(SOCKADDR_IN));
 local.sin_addr.s_addr = htonl(INADDR_ANY);
 local.sin_family = AF_INET;
 local.sin_port = htons(9989);

 int ret = bind(pDlg->m_svrSocket, (PSOCKADDR)&local, sizeof(SOCKADDR_IN));

 //绑定端口
    if (SOCKET_ERROR == ret)
    {
        char szError[256] = {0};
        sprintf(szError, "Bind Faild: %d", WSAGetLastError());
        AfxMessageBox(szError);
        return -1;
    }

    //监听
 ret = listen(pDlg->m_svrSocket, 10);
    if(SOCKET_ERROR == ret)
    {
        char szError[256] = {0};
        sprintf(szError, "Listen Faild: %d", WSAGetLastError());
        AfxMessageBox(szError);
        return -1;
    }

 // 通知上级线程 线程服务可以开始了
 pDlg->PostMessage(WM_SERVER_CREATED);

 while (pDlg->m_bServerRunning)
 {
  // 接收外部连接
  int iAddress = sizeof(SOCKADDR_IN);
  SOCKET sClient;
  SOCKADDR_IN addrClient;
  memset(&addrClient, 0, sizeof(SOCKADDR_IN));
  sClient = accept(pDlg->m_svrSocket, (PSOCKADDR)&addrClient, &iAddress);
        if (INVALID_SOCKET == sClient)
        {
  // AfxMessageBox("delete pClient");
   pDlg->PostMessage(WM_ACCEPT_CLOSE, 0, 0);
            break;
        }
        else
        {
   pDlg->PostMessage(WM_NEW_CLIENT, (WPARAM)sClient, (LPARAM)lParam);
  // char szRecvMsg[256] = {0};
  // char szOutMsg[256] = {0};

   //接收客户端内容:阻塞
  // sClient.Receive(szRecvMsg, 256);
  // sprintf(szOutMsg, "Receive Msg: %s  ", szRecvMsg);
  // AfxMessageBox("");

  // pDlg->GetDlgItemText(IDC_EDIT_LOG, strText);
  // strText += szOutMsg;
   //aDlg->SetDlgItemText(IDC_EDIT_LOG, strText);

   //发送内容给客户端
  // serverSocket.Send("Have Receive The Msg", 50);

   //关闭
  // sClient.Close();
  // serverSocket.Close();
        }
 }

 return -1;
}

void CXEIM_ChatroomDlg::ShowAndUpdate()
{
 PostMessage(XM_EMDBLCLICKTREE);
}


void CXEIM_ChatroomDlg::XDoubleClickUserList(WPARAM wParam, LPARAM lParam)
{
 ShowWindow(SW_SHOW);
 GetDlgItem(IDC_RICHEDIT2)->SetFocus();
}

 类似资料: