⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chatserverdoc.cpp

📁 chatserver源码
💻 CPP
字号:
// ChatServerDoc.cpp : implementation of the CChatServerDoc class
//

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

#include "ChatServerDoc.h"//添加的代码
#include "ChatServerView.h"//添加的代码

#include "Msg.h"//添加的代码
#include "SetupDlg.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)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
	ON_UPDATE_COMMAND_UI(ID_STATEMENT_NUM, OnUpdateMessages)//添加的代码
	ON_UPDATE_COMMAND_UI(ID_PEOPLE_NUM, OnUpdateConnections)//添加的代码
END_MESSAGE_MAP()

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

CChatServerDoc::CChatServerDoc()
{
	// TODO: add one-time construction code here
	m_pSocket = NULL;
}

CChatServerDoc::~CChatServerDoc()
{
	delete m_pSocket;
}

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

	CSetupDlg Dialog;

	if (Dialog.DoModal() == IDOK)
	{
		m_pSocket=new CListenSocket(this);
		if (m_pSocket->Create(Dialog.m_nPort,SOCK_STREAM,(LPCTSTR )"169.254.39.83"))
		{
			if (m_pSocket->Listen())
				return TRUE;
		}
	}
	return FALSE;
}



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

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

/////////////////////////////////////////////////////////////////////////////
// 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::DeleteContents() 
{
	delete m_pSocket;
	m_pSocket = NULL;          //释放监听Socket

	CString temp;
	if (temp.LoadString(IDS_SERVERSHUTDOWN))
		m_msgList.AddTail(temp);  //显示关闭了的信息于窗口中

	while(!m_connectionList.IsEmpty())
	{
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.RemoveHead();
		CMsg* pMsg = AssembleMsg(pSocket);  //释放每一个客户接收Socket    
		pMsg->m_bClose = TRUE;                //同时发送给每一个客户相应的信息
											  //可以发送信息给客户,使其进行关闭操作
		SendMsg(pSocket, pMsg);

		if (!pSocket->IsAborted())
		{
			pSocket->ShutDown();

			BYTE Buffer[50];

			while (pSocket->Receive(Buffer,50) > 0);

			delete pSocket;
		}
	}

	m_msgList.RemoveAll();

	if (!m_viewList.IsEmpty())
		((CEditView*)m_viewList.GetHead())->SetWindowText(_T(""));//在窗口上清空

	CDocument::DeleteContents();
}

void CChatServerDoc::UpdateClients()
{
	for(POSITION pos = m_connectionList.GetHeadPosition(); pos != NULL;)
	{
		CClientSocket* pSocket = (CClientSocket*)m_connectionList.GetNext(pos);
		CMsg* pMsg = AssembleMsg(pSocket);

		if (pMsg != NULL)
			SendMsg(pSocket, pMsg);
	}
}

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

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

void CChatServerDoc::ProcessPendingRead(CClientSocket* pSocket)
{
	do
	{
		CMsg* pMsg = ReadMsg(pSocket);

		if (pMsg->m_bClose)
		{
			CloseSocket(pSocket);
			break;
		}
	}
	while (!pSocket->m_pArchiveIn->IsBufferEmpty());

	UpdateClients();
}

CMsg* CChatServerDoc::AssembleMsg(CClientSocket* pSocket)//注意1:这个函数
{													   //的作用是给每个客户组装信息结构
	static CMsg msg;								   //从而为了下面的发送	

	msg.Init();

	if (pSocket->m_nMsgCount >= m_msgList.GetCount())//接收前的信息总数应该小于接收
		return NULL;						   //一个或几个(几个是由于有多个客户在发送信息)
											   //新信息之后的信息总数
											   //在这里每个客户接收Socket的m_nMsgCount
										       //都保存了一个时刻的服务器端的信息总数
	for (POSITION pos1 = m_msgList.FindIndex(pSocket->m_nMsgCount); pos1 != NULL;)
	{
		CString temp = m_msgList.GetNext(pos1);
		msg.m_msgList.AddTail(temp);         //注意:需要理解的是放了哪些串在msg的里面了
	}										//:是比接收前多出的那几个信息串
	pSocket->m_nMsgCount = m_msgList.GetCount();
	return &msg;
}

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

	TRY
	{
		pSocket->ReceiveMsg(&msg);//注意3:接收的是Msg结构,
										//包括了它的三个成员变量
						//而从客户端的发送函数可以看出,最新的串没有加入到信息List中。
		Message(msg.m_strText);//所以在这里只是处理这个最新的串,
							   //方式可以从下面的语句看出:把它放到信息List的最后。
		m_msgList.AddTail(msg.m_strText);//注意这个信息List是服务器端应用程序的
	}                                      //的信息List,它包括了所有客户的信息
	CATCH(CFileException, e)
	{
		CString strTemp;
		if (strTemp.LoadString(IDS_READERROR))
			Message(strTemp);

		msg.m_bClose = TRUE;
		pSocket->Abort();
	}
	END_CATCH

	return &msg;
}

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

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

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);
		if (pSock == pSocket)
		{
			m_connectionList.RemoveAt(temp);
			break;
		}
	}

	delete pSocket;
}

void CChatServerDoc::Message(LPCTSTR lpszMessage)
{
	((CChatServerView*)m_viewList.GetHead())->Message(lpszMessage);
}

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

void CChatServerDoc::OnUpdateMessages(CCmdUI* pCmdUI)//在状态栏中显示有多少的语句已经交流了
{
	pCmdUI->Enable(TRUE);

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

void CChatServerDoc::OnUpdateConnections(CCmdUI* pCmdUI)//在状态栏中显示有多少人在线
{
	pCmdUI->Enable(TRUE);

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

⌨️ 快捷键说明

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