// 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();
}