chatserverdoc.cpp

来自「基于winsock的聊天程序」· C++ 代码 · 共 549 行

CPP
549
字号
// ChatServerDoc.cpp : implementation of the CChatServerDoc class
//

#include "stdafx.h"
#include "ChatServer.h"

#include "ChatServerDoc.h"
#include "CntrItem.h"
#include "Msg.h"
#include "ChatServerView.h"
#include "logindlg.h"
#include "mainfrm.h"
#include "CleanDlg.h"
#include "brandCast.h"

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

/////////////////////////////////////////////////////////////////////////////
// CChatServerDoc

IMPLEMENT_DYNCREATE(CChatServerDoc, CRichEditDoc)

BEGIN_MESSAGE_MAP(CChatServerDoc, CRichEditDoc)
	//{{AFX_MSG_MAP(CChatServerDoc)
	ON_COMMAND(ID_SERVER_BRANDCAST, OnServerBrandcast)
	//}}AFX_MSG_MAP
	// Enable default OLE container implementation
	ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_LINKS, CRichEditDoc::OnUpdateEditLinksMenu)
	ON_COMMAND(ID_OLE_EDIT_LINKS, CRichEditDoc::OnEditLinks)
	ON_UPDATE_COMMAND_UI_RANGE(ID_OLE_VERB_FIRST, ID_OLE_VERB_LAST, CRichEditDoc::OnUpdateObjectVerbMenu)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChatServerDoc construction/destruction

CChatServerDoc::CChatServerDoc()
{
	// TODO: add one-time construction code here

	m_pSocket = NULL;
	m_lCount = 0;
}

CChatServerDoc::~CChatServerDoc()
{
	
	if(m_pSocket != NULL)
		delete m_pSocket;
	m_pSocket = NULL;
}

BOOL CChatServerDoc::OnNewDocument()
{
	if (!CRichEditDoc::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)
//Create server
	CLoginDlg dlg;
	while(TRUE)
	{
		if(dlg.DoModal()!=IDOK)
		{
			return FALSE;
		}
		m_pSocket = new CListeningSocket(this);
		if (m_pSocket->Create(dlg.m_nPort,SOCK_STREAM,dlg.m_strAddress))
		{
			if (m_pSocket->Listen())	
			{
				SetTitle("聊天工具服务器端");
				return TRUE;
			}
		}
	}
	return TRUE;
}

CRichEditCntrItem* CChatServerDoc::CreateClientItem(REOBJECT* preo) const
{
	// cast away constness of this
	return new CChatServerCntrItem(preo, (CChatServerDoc*) this);
}



/////////////////////////////////////////////////////////////////////////////
// CChatServerDoc serialization

void CChatServerDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}

	// Calling the base class CRichEditDoc enables serialization
	//  of the container document's COleClientItem objects.
	// TODO: set CRichEditDoc::m_bRTF = FALSE if you are serializing as text
	CRichEditDoc::Serialize(ar);
}

/////////////////////////////////////////////////////////////////////////////
// CChatServerDoc diagnostics

#ifdef _DEBUG
void CChatServerDoc::AssertValid() const
{
	CRichEditDoc::AssertValid();
}

void CChatServerDoc::Dump(CDumpContext& dc) const
{
	CRichEditDoc::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CChatServerDoc commands

void CChatServerDoc::DeleteContents() 
{
	//Before Server Exit,Send Exit-Message to all user!
	delete m_pSocket;
	m_pSocket = NULL;

	CString temp;
	temp="服务器已经关掉!";
	
	CMsg* pMsg = new CMsg;
	while(!m_connectionList.IsEmpty())
	{
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.RemoveHead();
		if(pSocket==NULL ) continue;
		if (pMsg == NULL) continue;
		pMsg->m_bClose = TRUE;
		pMsg->m_strFrom = pSocket->name;
		pMsg->m_strText = _TEXT("服务器已关闭");
		pMsg->m_strTo = _TEXT("所有人");
		pMsg->m_nType = -3;

		SendMsg(pSocket, pMsg);
		
		if(!pSocket->IsAborted())
		{
			pSocket->ShutDown();
			BYTE Buffer[50];
			while (pSocket->Receive(Buffer,50) > 0);
			delete pSocket;
		}
	}
	delete pMsg;
	
	if (!m_viewList.IsEmpty())
		((CRichEditView*)m_viewList.GetHead())->SetWindowText(_T(""));
	CDocument::DeleteContents();
}

void CChatServerDoc::UpdateClients()
{
//Update Message
	CMsg* pMsg = AssembleMsg(NULL);
	if(pMsg->m_nType>= 0)
		m_lCount ++;
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;)
	{
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.GetNext(pos);
		if (pMsg != NULL)
			SendMsg(pSocket, pMsg);
	}
}

void CChatServerDoc::ProcessPendingAccept() 
{
//Accept  new user
	CClientSocket* pSocket = new CClientSocket(this);

	if (m_pSocket->Accept(*pSocket))
	{
		pSocket->Init();
		m_connectionList.AddTail(pSocket);
	}
	else
		delete pSocket;
}

void CChatServerDoc::ProcessPendingRead(CClientSocket* pSocket)
{
//Read message
	if(pSocket != NULL)
	{
		do{
			CMsg* pMsg = ReadMsg(pSocket);
			if(pMsg == NULL) return;
			if (pMsg->m_bClose)	
			{
				CloseSocket(pSocket);
				pMsg->m_bClose = FALSE;
				break;
			}
			if(pMsg->m_nType == -1){
				UpdateList(pSocket);
			}
		}
		while (!pSocket->m_pArchiveIn->IsBufferEmpty());
	}	
	UpdateClients();
	OnUpdateMessages() ;//Update Messages number
	OnUpdateConnections() ;//Update Online user
}

CMsg* CChatServerDoc::AssembleMsg(CClientSocket* pSocket)
{
	static CMsg msg;
	
	CMsg* tmp;

	tmp = m_lsMsg.RemoveHead();
	if(tmp != NULL)
		memcpy(&msg, tmp, sizeof(CMsg));

	return &msg;
}

CMsg* CChatServerDoc::ReadMsg(CClientSocket* pSocket)
{
	//read message
	static CMsg msg;
	CClientSocket* pSock;
	TRY
	{
		pSocket->ReceiveMsg(&msg);
		if(msg.m_nType ==-1)
		{
			bool found=false;
			for(POSITION posname=m_connectionList.GetHeadPosition();posname;){				
				pSock = (CClientSocket*)m_connectionList.GetNext(posname);
				if(pSock->name==msg.m_strFrom ){
					found=true;
					pSocket->needdel=true;
					DeleteSocket();
					return NULL;
				}
			}
			if(found==false)
			{
				pSocket->name = msg.m_strFrom;
				pSocket->image = msg.m_dImage;
				Message("系统信息:",RGB(0,0,0));
				Message(msg.m_strFrom,RGB(255,0,0));
				Message("风尘仆仆地推门而入!\r\n",RGB(0,0,255));
			}
		}
		else if(msg.m_nType ==-2)
		{
			Message("系统信息:",RGB(0,0,0));
			Message(msg.m_strFrom,RGB(255,0,0));
			Message("静静地离开了,孤单的背影显得格外潇洒\r\n",RGB(0,0,255));
		}
		else if(msg.m_nType==-10)
		{
			Message("系统信息:",RGB(0,0,0));
			Message(msg.m_strText,msg.m_color);
			Message("\r\n",RGB(0,0,255));
		}
		int i = msg.m_nType;
		if(i >= 0 && i <= 32)
		{
			talk(i,msg.m_strFrom,msg.m_strTo,msg.m_strText,msg.m_color);
		}
		if(i>=-2 && i <= 32)
		{
			m_lsMsg.AddTail(&msg);
		}
	}
	CATCH(CFileException, e)
	{
		CString strTemp;
		if (strTemp.LoadString(IDS_READERROR))
			Message(strTemp,RGB(0,0,0));
		
		msg.m_bClose = TRUE;
		pSocket->Abort();
	}
	END_CATCH
	return &msg;
}

void CChatServerDoc::SendMsg(CClientSocket* pSocket, CMsg* pMsg)
{//Send message
	TRY
	{
		pSocket->SendMsg(pMsg);
	}
	CATCH(CFileException, e)
	{
		pSocket->Abort();

		CString strTemp;
		if (strTemp.LoadString(IDS_SENDERROR))
			Message(strTemp,RGB(0,0,0));
	}
	END_CATCH
}

void CChatServerDoc::CloseSocket(CClientSocket* pSocket)
{
	//Close Socket
	pSocket->Close();

	POSITION pos,temp;
	for(pos = m_connectionList.GetHeadPosition(); pos != NULL;)
	{
		temp = pos;
		CClientSocket* pSock = (CClientSocket*)m_connectionList.GetNext(pos);
		if (pSock == pSocket)
		{
			m_connectionList.RemoveAt(temp);
			break;
		}
	}

	delete pSocket;
}

void CChatServerDoc::Message(LPCTSTR lpszMessage,COLORREF clr)
{
	//Display Message
	((CChatServerView*)m_viewList.GetHead())->Message(lpszMessage,clr);
}


/////////////////////////////////////////////////////////////////////////////
// CServerDoc Handlers

void CChatServerDoc::OnUpdateMessages() 
{
	//Update chat messages number
	CString strTemp;
	wsprintf(strTemp.GetBuffer(50),"信息数: %d",m_lCount);
	CMainFrame *MFrame=(CMainFrame *)AfxGetMainWnd();
	MFrame->m_wndStatusBar.SetPaneText(2,strTemp);
	strTemp.ReleaseBuffer();
}

void CChatServerDoc::OnUpdateConnections() 
{
	//Update
	CString strTemp;
	wsprintf(strTemp.GetBuffer(50),"在线人数:%d",m_connectionList.GetCount());
	CMainFrame *MFrame=(CMainFrame *)AfxGetMainWnd();
	MFrame->m_wndStatusBar.SetPaneText(1,strTemp);
	strTemp.ReleaseBuffer();
}

void CChatServerDoc::talk(int type2, CString from1, CString to1, CString str1,COLORREF clr)
{
	//Display general message
	CString temp,to2,first,second;

	if(type2 > 32 || type2 < 0)
	   return;
	if(from1==to1)
	{
		Message(from1,RGB(255,0,0));
		Message("自言自语道:",RGB(0,0,255));
		Message(str1,clr);
		Message("\r\n",RGB(0,0,0));
		return;
	}
	temp.LoadString(IDS_TALK0 + type2);	
	int i=temp.Find(",");
	if(i!=-1)
	{
		first=temp.Left(i);
		if(i!=temp.GetLength()-1){
			second=temp.Mid(i+1);
			second+=":";
		}
		else{
			second=":";
		}
		Message(from1,RGB(0,0,0));
		Message(first,RGB(255,0,0));
		Message(to1,RGB(0,0,255));
		Message(second,RGB(255,0,0));
		Message(str1,clr);
		Message("\r\n",RGB(0,0,0));
	}
	else
	{
		first=temp;
		second=": ";
		Message(from1,RGB(0,0,0));
		Message(first,RGB(255,0,0));
		Message(second,RGB(0,0,255));
		Message(str1,clr);
		Message("\r\n",RGB(0,0,0));
	}
}

void CChatServerDoc::DeleteSocket()
{
	//delete user
	CClientSocket* pSock;
	POSITION pos, temp;
	for(pos = m_connectionList.GetHeadPosition(); pos != NULL;)
	{
		temp = pos;
		pSock = (CClientSocket*)m_connectionList.GetNext(pos);
	 	if (pSock->needdel==true)
		{
			m_connectionList.RemoveAt(temp);
			break;
		}
	}
	if(pSock==NULL) 
		return;
	CMsg* pMsg = new CMsg;
	pMsg->m_strFrom = _TEXT("系统信息:");
	pMsg->m_strTo = _TEXT("你");
	pMsg->m_bClose = TRUE;
	pMsg->m_nType =-9;
	pMsg->m_color = RGB(128,0,222);

	SendMsg(pSock, pMsg);
	if (!pSock->IsAborted()){
		pSock->ShutDown();
		BYTE Buffer[50];
		while (pSock->Receive(Buffer,50) > 0);
		delete pSock;
	}
}


void CChatServerDoc::UpdateList(CClientSocket* pSocket)//Update user list
{
	CMsg* pMsg = new CMsg;
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;){
		CClientSocket* pSock = (CClientSocket*)m_connectionList.GetNext(pos);
		pMsg->m_strFrom = pSock->name;
		pMsg->m_nType = -8;
		pMsg->m_dImage = pSock->image;
		SendMsg(pSocket, pMsg);
	}
}

void CChatServerDoc::Clean() 
{
	CCleanDlg clean;
    CString name; 
	if(clean.DoModal()==IDOK){
		if(clean.m_cleanname=="") return;
		CClientSocket* pSock;
		POSITION pos, temp,posname;
		bool found=false;
		for(posname = m_connectionList.GetHeadPosition(); posname;)
		{				
			pSock = (CClientSocket*)m_connectionList.GetNext(posname);
			
			if(pSock->name == clean.m_cleanname)
				found=true;
		}
		if(!found){
			Message("系统信息:",RGB(0,0,0));
			Message("不能进行'踢'操作!\r\n",RGB(255,0,0));
			return;
		}
		//type为-7表示把人踢出站外,先给每个人发一个通知,从在线列表里
		//删除该人,
		CMsg* pMsg = new CMsg;
		for(pos = m_connectionList.GetHeadPosition(); pos != NULL;)
		{
			temp = pos;
			pSock = (CClientSocket*)m_connectionList.GetNext(pos);
			pMsg->m_bClose = FALSE;
			pMsg->m_nType = -7;
			pMsg->m_strFrom = clean.m_cleanname;
			SendMsg(pSock, pMsg);
		}
		
		//第二次通知该人,你已经被踢出了,同时关闭与它的Socket连接
		for(pos = m_connectionList.GetHeadPosition(); pos != NULL;)
		{
			temp = pos;
			pSock = (CClientSocket*)m_connectionList.GetNext(pos);
			if (pSock->name == clean.m_cleanname)
			{		
				if(pSock == NULL) return;
				pMsg->m_bClose = TRUE;
				pMsg->m_nType = -5;
				pMsg->m_strFrom = clean.m_cleanname;
				SendMsg(pSock, pMsg);
				m_connectionList.RemoveAt(temp);
				if (!pSock->IsAborted())
				{
					pSock->ShutDown();
					BYTE Buffer[50];
					while (pSock->Receive(Buffer,50) > 0);
					delete pSock;
				}
				
				Message("系统信息:",RGB(0,0,0));
				Message("聊天室掌门人以一招'佛山无影脚',将",RGB(0,0,255));
				Message(clean.m_cleanname,RGB(255,0,255));
				Message("踢出门外\r\n",RGB(0,0,255));
			}
		}
		delete pMsg;
	}
}

void CChatServerDoc::OnServerBrandcast() 
{
	// TODO: Add your command handler code here
	//Send BroadCast
	CBrandCast dlg;
	if(dlg.DoModal()!=IDOK)
	{
		return;
	}
	CMsg* pMsg = new CMsg;

	pMsg->m_color=RGB(0,0,0);
	pMsg->m_strFrom="系统信息:";
	pMsg->m_strText=dlg.m_strBrandCast;
	pMsg->m_strTo=" 所有人";
	pMsg->m_nType=-10;
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;)
	{
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.GetNext(pos);
		if (pMsg != NULL)
			SendMsg(pSocket, pMsg);
	}
	Message("系统信息:",pMsg->m_color);
	Message(pMsg->m_strText,pMsg->m_color);
	Message("\r\n",pMsg->m_color);
	delete pMsg;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?