www.gusucode.com > 一些VC++网络编程实例源代码-源码程序 > 一些VC++网络编程实例源代码-源码程序\code\第三章\chat\chatserver\Srvrdoc.cpp

    //Download by http://www.NewXing.com
// srvrdoc.cpp : implementation of the CServerDoc class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1997 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "chatsrvr.h"

#include "srvrdoc.h"
#include "srvrvw.h"

#include "message.h"
#include "CleanDlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CServerDoc

IMPLEMENT_DYNCREATE(CServerDoc, CDocument)

BEGIN_MESSAGE_MAP(CServerDoc, CDocument)
	//{{AFX_MSG_MAP(CServerDoc)
	ON_COMMAND(ID_CLEAN, OnClean)
	//}}AFX_MSG_MAP
	ON_UPDATE_COMMAND_UI(ID_MESSAGES, OnUpdateMessages)
	ON_UPDATE_COMMAND_UI(ID_CONNECTIONS, OnUpdateConnections)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CServerDoc construction/destruction

CServerDoc::CServerDoc()
{
	m_pSocket = NULL;
	m_lCount = 0;
}

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

//
//这里开始打开该端口的网络服务,等待客户的连接
//
BOOL CServerDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;
	
	m_pSocket = new CListeningSocket(this);
	if (m_pSocket->Create(PORT)){
		if (m_pSocket->Listen())
			return TRUE;
	}
	return FALSE;
}

//该函数在有客户连接时关闭服务器时调用
void CServerDoc::DeleteContents() 
{
	delete m_pSocket;
	m_pSocket = NULL;

	CString temp;
	temp="服务器已经关掉!";
	
	CMessage* pMsg = new CMessage;
	while(!m_connectionList.IsEmpty())
	{
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.RemoveHead();
		if(pSocket==NULL ) continue;
		if (pMsg == NULL) continue;
		pMsg->m_bClose = TRUE;
		pMsg->from = pSocket->name;
		pMsg->m_strText = _TEXT("服务器已关闭");
		pMsg->to = _TEXT("所有人");
		pMsg->type = -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())
		((CEditView*)m_viewList.GetHead())->SetWindowText(_T(""));

	CDocument::DeleteContents();
}

/////////////////////////////////////////////////////////////////////////////
// CServerDoc serialization

void CServerDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// CEditView contains an edit control which handles all serialization
		((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);
	}
}

/////////////////////////////////////////////////////////////////////////////
// CServerDoc diagnostics

#ifdef _DEBUG
void CServerDoc::AssertValid() const
{
	CDocument::AssertValid();
}

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

/////////////////////////////////////////////////////////////////////////////
// CServerDoc Operations

void CServerDoc::UpdateClients()
{
	CMessage* pMsg = AssembleMsg(NULL);
	if(pMsg->type >= 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 CServerDoc::ProcessPendingAccept() 
{
	CClientSocket* pSocket = new CClientSocket(this);

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

void CServerDoc::ProcessPendingRead(CClientSocket* pSocket)
{
	if(pSocket != NULL)
	{
		do{
			CMessage* pMsg = ReadMsg(pSocket);
			if(pMsg == NULL) return;
			if (pMsg->m_bClose)	
			{
				CloseSocket(pSocket);
				pMsg->m_bClose = FALSE;
				break;
			}
			if(pMsg->type == -1){
				UpdateList(pSocket);
			}
		}
		while (!pSocket->m_pArchiveIn->IsBufferEmpty());
	}	
	UpdateClients();
}

CMessage* CServerDoc::AssembleMsg(CClientSocket* pSocket)
{
	static CMessage msg;
	
	CMessage* tmp;

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

	return &msg;
}

CMessage* CServerDoc::ReadMsg(CClientSocket* pSocket)
{
	static CMessage msg;
	CClientSocket* pSock;
	TRY
	{
		pSocket->ReceiveMsg(&msg);
		if(msg.type == -1)
		{
			bool found=false;
			for(POSITION posname=m_connectionList.GetHeadPosition();posname;){				
				pSock = (CClientSocket*)m_connectionList.GetNext(posname);
				if(pSock->name==msg.from ){
					found=true;
					pSocket->needdel=true;
					DelSocket();
					return NULL;
				}
			}
			if(found==false)
			{
				pSocket->name = msg.from;
				pSocket->image = msg.image;
				Message1(msg.from);
				Message1("风尘仆仆地推门而入\r\n");
			}
		}
		if(msg.type == -2)
		{
			Message1(msg.from);
			Message1("静静地离开了,孤单的背影显得格外潇洒\r\n");
		}
		int i = msg.type;
		if(i >= 0 && i <= 32){
			talk(i,msg.from,msg.to,msg.m_strText);
		}
		if(i >= -2 && i <= 32){
			m_lsMsg.AddTail(&msg);
		}
	}
	CATCH(CFileException, e)
	{
		CString strTemp;
		if (strTemp.LoadString(IDS_READERROR))
			Message(strTemp);
		
		msg.m_bClose = TRUE;
		pSocket->Abort();
	}
	END_CATCH
	return &msg;
}

void CServerDoc::SendMsg(CClientSocket* pSocket, CMessage* pMsg)
{
	TRY
	{
		pSocket->SendMsg(pMsg);
	}
	CATCH(CFileException, e)
	{
		pSocket->Abort();

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

void CServerDoc::CloseSocket(CClientSocket* pSocket)
{
	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 CServerDoc::Message(LPCTSTR lpszMessage)
{
	((CServerView*)m_viewList.GetHead())->Message(lpszMessage);
}

void CServerDoc::Message1(LPCTSTR lpszMessage)
{
	((CServerView*)m_viewList.GetHead())->Message1(lpszMessage);
}
/////////////////////////////////////////////////////////////////////////////
// CServerDoc Handlers

void CServerDoc::OnUpdateMessages(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(TRUE);

	CString strFmt;
	if (strFmt.LoadString(IDS_MESSAGESFMT))
	{
		CString strTemp;
		wsprintf(strTemp.GetBuffer(50),strFmt,m_lCount);
        strTemp.ReleaseBuffer();
		pCmdUI->SetText(strTemp);
	}
}

void CServerDoc::OnUpdateConnections(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(TRUE);

	CString strFmt;
	if (strFmt.LoadString(IDS_CONNECTIONSFMT))
	{
		CString strTemp;
		wsprintf(strTemp.GetBuffer(50),strFmt,m_connectionList.GetCount());
		strTemp.ReleaseBuffer();
		pCmdUI->SetText(strTemp);
	}
}

void CServerDoc::talk(int type2, CString from1, CString to1, CString str1)
{
	CString temp,to2,first,second;

	if(type2 > 32 || type2 < 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=":";
		}
		Message1(from1);
		Message1(first);
		Message1(to1);
		Message1(second);
		Message1(str1);
		Message1("\r\n");
	}
	else{
		first=temp;
		second=": ";
		Message1(from1);
		Message1(first);
		Message1(second);
		Message1(str1);
		Message1("\r\n");
	}
}

void CServerDoc::DelSocket()
{
	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;
	CMessage* pMsg = new CMessage;
	pMsg->from = _TEXT("系统");
	pMsg->to = _TEXT("你");
	pMsg->m_bClose = TRUE;
	pMsg->type = -9;
	pMsg->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 CServerDoc::OnClean() 
{
	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){
			Message1("系统:");
			Message1("不能进行'踢'操作!\r\n");
			return;
		}
		//type为-7表示把人踢出站外,先给每个人发一个通知,从在线列表里
		//删除该人,
		CMessage* pMsg = new CMessage;
		for(pos = m_connectionList.GetHeadPosition(); pos != NULL;)
		{
			temp = pos;
			pSock = (CClientSocket*)m_connectionList.GetNext(pos);
			pMsg->m_bClose = FALSE;
			pMsg->type = -7;
			pMsg->from = 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->type = -7;
				pMsg->from = 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;
				}
				
				Message1("系统:聊天室掌门人以一招'佛山无影脚',将");
				Message1(clean.m_cleanname);
				Message1("踢出门外\r\n");
			}
		}
		delete pMsg;
	}
}

void CServerDoc::UpdateList(CClientSocket* pSocket)
{
	CMessage* pMsg = new CMessage;
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;){
		CClientSocket* pSock = (CClientSocket*)m_connectionList.GetNext(pos);
		pMsg->from = pSock->name;
		pMsg->type = -8;
		pMsg->image = pSock->image;
		SendMsg(pSocket, pMsg);
	}
}

void CServerDoc::Clean()
{
	OnClean();
}