www.pudn.com > 3.rar > ChatServerDoc.cpp


// ChatServerDoc.cpp : implementation of the CChatServerDoc class 
// 
 
#include "stdafx.h" 
#include "ChatServer.h" 
 
#include "ChatServerDoc.h" 
 
#include "MainFrm.h" 
#include"PortDlg.h" 
#include "ChattersListView.h" 
#include "ChatView.h" 
#include "ListeningSocket.h" 
#include "ClientSocket.h" 
#include "Msg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CChatServerDoc 
 
IMPLEMENT_DYNCREATE(CChatServerDoc, CDocument) 
 
BEGIN_MESSAGE_MAP(CChatServerDoc, CDocument) 
	//{{AFX_MSG_MAP(CChatServerDoc) 
	ON_COMMAND(ID_SETPORT, OnSetport) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
#define LEAVING_CHAT          1 
#define SENDING_CHATTERS_LIST 2 
#define SENDING_NICKNAME      3 
#define NORMAL_MESSAGE        4 
#define USED_NAME			  5 
///////////////////////////////////////////////////////////////////////////// 
// CChatServerDoc construction/destruction 
 
CChatServerDoc::CChatServerDoc() 
{ 
	// TODO: add one-time construction code here 
	m_pSocket = NULL; 
	m_msgList.RemoveAll(); 
	m_connectionList.RemoveAll(); 
	bIsNewChatter = TRUE; 
	m_ChattersList = ""; 
} 
 
CChatServerDoc::~CChatServerDoc() 
{ 
} 
 
BOOL CChatServerDoc::OnNewDocument() 
{ 
	if (!CDocument::OnNewDocument()) 
		return FALSE; 
 
	// TODO: add reinitialization code here 
	// (SDI documents will reuse this document) 
 
	return TRUE; 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CChatServerDoc serialization 
 
void CChatServerDoc::Serialize(CArchive& ar) 
{ 
	if (ar.IsStoring()) 
	{ 
		// TODO: add storing code here 
	} 
	else 
	{ 
		// TODO: add loading code here 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CChatServerDoc diagnostics 
 
#ifdef _DEBUG 
void CChatServerDoc::AssertValid() const 
{ 
	CDocument::AssertValid(); 
} 
 
void CChatServerDoc::Dump(CDumpContext& dc) const 
{ 
	CDocument::Dump(dc); 
} 
#endif //_DEBUG 
 
///////////////////////////////////////////////////////////////////////////// 
// CChatServerDoc commands 
 
void CChatServerDoc::OnSetport()  
{ 
	// TODO: Add your command handler code here 
	CPortDlg dlg; 
	if(dlg.DoModal() == IDOK) 
	{ 
		//创建一个新的类进行监听 
		m_pSocket = new CListeningSocket(this); 
		if (m_pSocket->Create(dlg.m_Port)) 
		{ 
			if (m_pSocket->Listen()) 
				return; 
		} 
	} 
} 
 
void CChatServerDoc::ProcessAccept() 
{ 
	//创建一个新的socket来处理与客户端的数据交互 
	CClientSocket* pSocket = new CClientSocket(this); 
	//如果接受客户端的连接请求 
	if (m_pSocket->Accept(*pSocket)) 
	{ 
		//初始化 
		pSocket->Init(); 
		//将此连接socket加入连接链表中 
		m_connectionList.AddTail(pSocket); 
	}	 
	//如果不接受连接 
	else 
		delete pSocket; 
} 
 
void CChatServerDoc::ProcessReceive(CClientSocket* pSocket) 
{ 
	CMsg* pMsg;  //接收的消息 
	CString sName;  //用户名 
	BOOL bIsUsedName = FALSE;  //用户名是否已使用 
	bIsNewChatter = FALSE;  //是否新用户 
 
	do 
	{ 
		//接收消息 
		pMsg = ReadMsg(pSocket); 
		//如果此消息是发送的新的用户名(在用户登录时客户端先发此消息) 
		if(pMsg->code == SENDING_NICKNAME) 
		{ 
			sName = pMsg->m_strText; 
			bIsNewChatter = TRUE; 
			//检查此用户名是否已使用 
			if(IsUsedName(sName)) 
				bIsUsedName = TRUE; 
		} 
		//如果连接已关闭则退出 
		if (pMsg->m_bClose) 
		{ 
			break; 
		} 
	} 
	while (!pSocket->m_pArchiveIn->IsBufferEmpty()); 
 
	//如果是用户登录 
	if(bIsNewChatter) 
	{ 
		//如果此用户名没有被使用 
		if(!bIsUsedName) 
		{ 
			//发送消息通知各客户端 
			pMsg->code = SENDING_CHATTERS_LIST; 
			m_ChattersList += sName + ":"; 
			pMsg->m_strText = m_ChattersList; 
			SendForNewcomer(pMsg); 
		} 
		//如果用户名已使用 
		else 
		{ 
			//发消息通知此客户端 
			CMsg* msg = new CMsg; 
			msg->Init(); 
			msg->code =  USED_NAME; 
			CString string; 
			string.Format("用户名已被使用!"); 
			msg->m_strText = string; 
			SendMsg(pSocket, msg); 
		} 
		bIsNewChatter = FALSE; 
		bIsUsedName = FALSE; 
	} 
 
	//如果消息表明该客户端已关闭连接 
	if (pMsg->m_bClose) 
	{ 
		//发送消息通知各客户端 
		SendToAllClients(NORMAL_MESSAGE); 
		//在视图中将该用户删除 
		DeleteChatter(pMsg); 
		//关闭连接 
		CloseSocket(pSocket); 
		//通知各客户端更新用户列表 
		SendToAllClients(SENDING_CHATTERS_LIST); 
	} 
	//否则是普通消息,发送给各客户端 
	else 
		SendToAllClients(NORMAL_MESSAGE); 
} 
 
CMsg* CChatServerDoc::ReadMsg(CClientSocket* pSocket) 
{ 
	static CMsg msg; 
	TRY 
	{ 
		//接收数据 
		pSocket->ReceiveMsg(&msg); 
		//如果是新用户登录则更新用户列表 
		if(msg.code == SENDING_NICKNAME) 
		{ 
			UpdateChattersListView(msg.m_strText , pSocket); 
		} 
		//如果是普通信息则更新聊天信息列表,并将信息加入到m_msgList链表中 
		if(msg.code == NORMAL_MESSAGE) 
		{ 
			UpdateMessageView(msg.m_strText); 
			m_msgList.AddTail(msg.m_strText); 
		} 
	} 
	CATCH(CFileException, e) 
	{ 
		CString strTemp; 
		strTemp.Format("无法读取数据!"); 
		UpdateMessageView(strTemp); 
		msg.m_bClose = TRUE; 
	} 
	END_CATCH 
	return &msg; 
} 
 
void CChatServerDoc::SendMsg(CClientSocket* pSocket, CMsg* pMsg) 
{ 
	TRY 
	{ 
		//调用CClientSocket的函数发送消息 
		pSocket->SendMsg(pMsg); 
	} 
	CATCH(CFileException, e) 
	{ 
		CString strTemp; 
		strTemp.Format("无法发送数据!"); 
		UpdateMessageView(strTemp); 
	} 
	END_CATCH 
} 
 
BOOL CChatServerDoc::IsUsedName(CString sNickName) 
{ 
	CString tempStr, tempList, sName; 
	tempStr = ""; 
	tempList = m_ChattersList; 
	do 
	{ 
		//利用“:”得到名字并查找(客户端发送的消息前面都有用户名加“:”) 
		sName = tempList.Left(tempList.Find(":", 0)); 
		tempList = tempList.Mid(tempList.Find(":", 0) + 1); 
		//找到则返回真 
		if(sName == sNickName) 
			return TRUE; 
	}while(tempList.Find(":" , 0) != -1); 
	//未被使用则返回假 
	return FALSE; 
} 
 
CMsg* CChatServerDoc::AssembleMsg(CClientSocket* pSocket , int nCode) 
{ 
	static CMsg msg; 
	msg.Init(); 
	for (POSITION pos1 = m_msgList.FindIndex(pSocket->m_nMsgCount); pos1 != NULL;) 
	{ 
		//信息内容 
		msg.m_strText = m_msgList.GetNext(pos1);	  
		//信息类型 
		msg.code = nCode; 
	} 
	pSocket->m_nMsgCount = m_msgList.GetCount(); 
	return &msg; 
} 
 
void CChatServerDoc::SendForNewcomer(CMsg* pMsg) 
{ 
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;) 
	{ 
		//对每个客户端都发送信息 
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.GetNext(pos); 
		if (pSocket != NULL) 
			SendMsg(pSocket, pMsg); 
	} 
} 
 
void CChatServerDoc::SendToAllClients(int nCode) 
{ 
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;) 
	{ 
		//得到每个客户端 
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.GetNext(pos); 
		//封装信息 
		CMsg* pMsg = AssembleMsg(pSocket, nCode); 
		//发送信息 
		if (pMsg != NULL) 
			SendMsg(pSocket, pMsg); 
	} 
} 
 
void CChatServerDoc::UpdateMessageView(LPCTSTR lpszMessage) 
{ 
	for(POSITION pos=GetFirstViewPosition();pos!=NULL;) 
	{ 
		CView* pView = GetNextView(pos); 
		CChatView* pChatView = DYNAMIC_DOWNCAST(CChatView, pView); 
		if (pChatView != NULL) 
			pChatView->ShowMessage(lpszMessage); 
	} 
} 
 
void CChatServerDoc::UpdateChattersListView(CString sName , CClientSocket* pSocket) 
{ 
	CString sIPAddress; 
	UINT iPort; 
	//得到IP地址和端口号 
	pSocket->GetPeerName(sIPAddress , iPort);	 
	for(POSITION pos=GetFirstViewPosition();pos!=NULL;) 
	{ 
		CView* pView = GetNextView(pos); 
		CChattersListView* pChattersListView = DYNAMIC_DOWNCAST(CChattersListView, pView); 
		//更新用户列表 
		if (pChattersListView != NULL) 
			pChattersListView->AddChatter(sName , sIPAddress , iPort); 
	}	 
} 
 
void CChatServerDoc::CloseSocket(CClientSocket* pSocket) 
{ 
	//关闭连接 
	pSocket->Close(); 
	POSITION pos,temp; 
	for(pos = m_connectionList.GetHeadPosition(); pos != NULL;) 
	{ 
		temp = pos; 
		CClientSocket* pSock = (CClientSocket*)m_connectionList.GetNext(pos); 
		//将此socket从连接链表中删除 
		if (pSock == pSocket) 
		{ 
			m_connectionList.RemoveAt(temp); 
			break; 
		} 
	} 
	delete pSocket; 
	//如果没有连接则清空连接链表 
	if(m_connectionList.GetCount() == 0) 
		m_msgList.RemoveAll(); 
} 
 
void CChatServerDoc::DeleteChatter(CMsg* pMsg) 
{ 
	//得到要删除的用户名 
	CString sNickName = pMsg->m_strText.Left(pMsg->m_strText.Find(":", 0)); 
	POSITION pos; 
	for(pos=GetFirstViewPosition();pos!=NULL;) 
	{ 
		CView* pView = GetNextView(pos); 
		CChattersListView* pChattersListView = DYNAMIC_DOWNCAST(CChattersListView, pView); 
		//在用户列表视图中将其删除 
		if (pChattersListView != NULL) 
			pChattersListView->DeleteChatter(sNickName); 
	}	 
	 
	CString tempStr, sName, tempList; 
	tempStr = ""; 
	tempList = m_ChattersList; 
	//得到除去此用户名之外的所有用户名 
	do 
	{ 
		sName = tempList.Left(tempList.Find(":", 0)); 
		tempList = tempList.Mid(tempList.Find(":", 0) + 1); 
		if(sName != sNickName) 
			tempStr += sName + ":"; 
	}while(tempList.Find(":" , 0) != -1); 
	m_ChattersList = tempStr; 
	//加入到信息链表和信息内容中 
	//接下来要对各客户端发送这些用户名,以使各客户端更新用户列表 
	pMsg->m_strText = m_ChattersList; 
	m_msgList.AddTail(m_ChattersList); 
} 
 
void CChatServerDoc::DeleteContents() 
{ 
	if(m_pSocket == (CListeningSocket*)NULL) 
		return; 
	//删除监听socket 
	delete m_pSocket; 
	m_pSocket = NULL; 
 
	CString temp; 
	temp.Format("服务器已关闭"); 
	m_msgList.AddTail(temp); 
 
	//对当前连接的每个客户端发送信息后关闭与该客户端的连接 
	while(!m_connectionList.IsEmpty()) 
	{ 
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.RemoveHead(); 
		CMsg* pMsg = AssembleMsg(pSocket , NORMAL_MESSAGE); 
		pMsg->m_bClose = TRUE; 
		SendMsg(pSocket, pMsg); 
		pSocket->ShutDown(2); 
		delete pSocket; 
	} 
	//清空所有信息 
	m_msgList.RemoveAll(); 
	CDocument::DeleteContents(); 
}