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

📄 serverview.cpp

📁 一个类似QQ的聊天程序
💻 CPP
字号:
// ServerView.cpp : implementation of the CServerView class
//

#include "stdafx.h"
#include "Server.h"

#include "ServerDoc.h"
#include "ServerView.h"

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

/////////////////////////////////////////////////////////////////////////////
// CServerView

IMPLEMENT_DYNCREATE(CServerView, CScrollView)

BEGIN_MESSAGE_MAP(CServerView, CScrollView)
//{{AFX_MSG_MAP(CServerView)
ON_COMMAND(ID_SERVER_CLOSE, OnServerClose)
ON_COMMAND(ID_SERVER_OPEN, OnServerOpen)
ON_UPDATE_COMMAND_UI(ID_SERVER_OPEN, OnUpdateServerOpen)
ON_UPDATE_COMMAND_UI(ID_SERVER_CLOSE, OnUpdateServerClose)
//}}AFX_MSG_MAP

// START CUSTOM CODE: Server Code	
ON_MESSAGE(WM_SERVER_ACCEPT, OnServerAccept) 
ON_MESSAGE(WM_CLIENT_READ, OnClientRead) 
ON_MESSAGE(WM_CLIENT_READCLOSE, OnClientReadClose) 
// END MODIFICATIONS: Server Code

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CServerView construction/destruction

CServerView::CServerView()
{
	// TODO: add construction code here
	m_bServerIsOpen = FALSE;
	for(int i=0;(i<MAXClient);i++) m_aClientSocket[i]=INVALID_SOCKET;
	
}

CServerView::~CServerView()
{
		
	if (m_bServerIsOpen)
		closesocket(m_pDoc->m_hServerSocket);
	
	for(int i=0;i<MAXClient;i++)
	{
		
		if (m_aClientSocket[i] != INVALID_SOCKET)
		{
			closesocket(m_aClientSocket[i]);
			m_aClientSocket[i] = INVALID_SOCKET;
		}
	}
}

BOOL CServerView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
	
	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CServerView drawing

void CServerView::OnDraw(CDC* pDC)
{
	CServerDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	
	// TODO: add draw code for native data here
	TEXTMETRIC tm;
	int iYValue;
	
	pDC->GetTextMetrics(&tm);
	iYValue = 0;
	
	for (int iLine = 0; iLine <= m_pDoc->m_lLineNumber; iLine++)
	{
		pDC->TextOut(0,iYValue, m_pDoc->m_csText[iLine], m_pDoc->m_csText[iLine].GetLength());
		iYValue += tm.tmHeight;
	}
	
	SetScrollSizes(MM_TEXT, CSize(0, ((int) m_pDoc->m_lLineNumber+1) * tm.tmHeight));
	return;
}

void CServerView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);

	m_pDoc = GetDocument();
	m_pDoc->SetTitle("Server");
	
	m_pParentWnd = GetParent();
	m_pParentMenu = m_pParentWnd->GetMenu();
	
	// Setup the server window
	TEXTMETRIC tm;
	CRect rectServerSize;
	CClientDC dc(this);
	
	dc.GetTextMetrics(&tm);
	SetScrollSizes( MM_TEXT, CSize(0,0), CSize(0,(MAX_LINES*tm.tmHeight)), CSize(0, tm.tmHeight));
	GetWindowRect( rectServerSize );
	GetParentFrame()->MoveWindow( rectServerSize.left, rectServerSize.top, (MAX_COLUMNS*tm.tmAveCharWidth), (24*tm.tmHeight), TRUE);
		  
	return;
}

/////////////////////////////////////////////////////////////////////////////
// CServerView diagnostics

#ifdef _DEBUG
void CServerView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CServerView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CServerDoc* CServerView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CServerDoc)));
	return (CServerDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CServerView message handlers

void CServerView::PrintString(CString csString)
{
	if (csString.GetLength() == 0)
		return;
	
	// Print each character in the string except the last one
	for (int iChar = 0; iChar < (csString.GetLength()-1); iChar++)
		PrintChar(csString[iChar], FALSE);	// Don't update scroll bar
	
	// Update the scroll bar when reaching the last character
	PrintChar(csString[iChar], TRUE);
	m_pDoc->UpdateAllViews(NULL, 0L, 0);
	return;
}

void CServerView::PrintString(LPSTR lpszString)
{
	if (*lpszString == NULL)
		return;
	
	// Print each character in the string except the last one
	for (int iChar = 0; lpszString[iChar+1] != NULL; iChar++)
		PrintChar(lpszString[iChar], FALSE);	// Don't update scroll bar
	
	// Update the scroll bar when reaching the last character
	PrintChar( lpszString[iChar], TRUE);
	m_pDoc->UpdateAllViews(NULL, 0L, 0);
	return;
}

void CServerView::PrintChar(char chChar, BOOL bLastChar)
{
	// Ignore carriage-returns, the following statements detect new-lines.
	if (chChar =='\r')
		return;
	
	CClientDC dc(this);
	TEXTMETRIC tm;
	CPoint pt, ptOrigin;
	CRect rectServerSize;
	
	OnPrepareDC(&dc);       
	dc.GetTextMetrics(&tm);                        
	
	if (chChar =='\n')
	{  
		// Move to column zero for a new line.
		m_pDoc->m_lColumnNumber = 0;
		if (m_pDoc->m_lLineNumber == (MAX_LINES-1))
		{
			for (int iLine = 0; iLine < MAX_LINES; iLine++)
				m_pDoc->m_csText[iLine] = m_pDoc->m_csText[iLine+1];
	          	
			m_pDoc->m_csText[iLine].Empty();
			m_pDoc->UpdateAllViews(this, 0L, 0);
		}
		else
			m_pDoc->m_lLineNumber++;
		
		SetScrollSizes( MM_TEXT, CSize(0, ((int) m_pDoc->m_lLineNumber+1) * tm.tmHeight));
	}
	else
	  	{
		if (m_pDoc->m_lColumnNumber++ >= MAX_COLUMNS)
		{
			m_pDoc->m_lColumnNumber = 1;
			if (m_pDoc->m_lLineNumber == (MAX_LINES-1))
			{
				for (int iLine = 0; iLine < MAX_LINES; iLine ++)
					m_pDoc->m_csText[iLine] = m_pDoc->m_csText[iLine+1];
				
				m_pDoc->m_csText[iLine].Empty();
				m_pDoc->UpdateAllViews(this, 0L, 0);
			}
			else
				m_pDoc->m_lLineNumber++;
		}   
		
		m_pDoc->m_csText[m_pDoc->m_lLineNumber] += chChar;
		
		if (bLastChar)
			dc.TextOut(0, (int) m_pDoc->m_lLineNumber * tm.tmHeight,
			m_pDoc->m_csText[m_pDoc->m_lLineNumber],
			m_pDoc->m_csText[m_pDoc->m_lLineNumber].GetLength());
		
	}                             
	
	// If last character then update the position on the scroll bar
	if (bLastChar)
	{
		pt = GetScrollPosition();             
		if ((int) m_pDoc->m_lLineNumber * tm.tmHeight < pt.y)
		{
			pt.y = (int) m_pDoc->m_lLineNumber * tm.tmHeight;
			ScrollToPosition(pt);
		}
		else
		{
			CScrollView::GetClientRect( rectServerSize);                            
			if ((((int)m_pDoc->m_lLineNumber * tm.tmHeight) + tm.tmHeight) > rectServerSize.bottom)
			{
				ptOrigin = dc.GetViewportOrg();  
				pt.x = ptOrigin.x;
				pt.y = ((int) m_pDoc->m_lLineNumber * tm.tmHeight) + tm.tmHeight - rectServerSize.bottom;
				ScrollToPosition(pt );
			}
		}
	}
	return;
}

void CServerView::ReportWinsockErr(LPSTR lpszErrorMsg)
{
	wsprintf(m_chMsgBuffer, "\nWinsock error %d: %s\n\n", WSAGetLastError(), lpszErrorMsg);
	PrintString("==>>");
	PrintString((LPSTR)lpszErrorMsg);
//	MessageBeep(MB_ICONSTOP);
	MessageBox(m_chMsgBuffer,  AfxGetAppName(), MB_OK|MB_ICONSTOP);
	return;   
}

/////////////////////////////////////////////////////////////////////////////
// CServerView message handlers

LRESULT CServerView::OnServerAccept(WPARAM wParam, LPARAM lParam)
{ 
	int iErrorCode;
	int nLength = sizeof(SOCKADDR);
	int i;
	
	if (WSAGETSELECTERROR(lParam))
	{
		ReportWinsockErr("Error detected on entry into OnServerAccept.");
		return 0L;
	}
	
	if (WSAGETSELECTEVENT(lParam) == FD_ACCEPT)
	{
		for(i=0;(i<MAXClient)&&(m_aClientSocket[i]!=INVALID_SOCKET);i++) ;
		if(i==MAXClient) return 0L;
		
	//	PrintString("==>>一个客户连接成功!\n");						
		m_aClientSocket[i] = accept(m_pDoc->m_hServerSocket, (LPSOCKADDR)&m_sockClientAddr, (LPINT)&nLength);
		
		if (m_aClientSocket[i] == INVALID_SOCKET)
		{
			ReportWinsockErr("Server socket failed to accept connection.");
			return 0L;
		}
		
		CString csDottedDecimal = "一个客户进行了连接 ";
		csDottedDecimal += inet_ntoa(m_sockClientAddr.sin_addr);
		csDottedDecimal += "\n";
		PrintString("==>>"+csDottedDecimal);	
		WSAAsyncSelect(m_aClientSocket[i],m_hWnd,WM_CLIENT_READCLOSE,FD_READ|FD_CLOSE);
		
		CString csText = "服务器连接成功";
		LPSTR lpszResponse = csText.GetBuffer(1000);
		
		iErrorCode = send( m_aClientSocket[i], lpszResponse, lstrlen(lpszResponse), NO_FLAGS);    
		if (iErrorCode == SOCKET_ERROR)
			ReportWinsockErr("Error sending response to client.");
		//else
		//	PrintString("Response sent!\n");
		//OnClientClose();
	}
	return 0L;
}


void CServerView::OnServerClose() 
{ 
	char csText[20] = "服务器关闭";


	for(int j=0;(j<MAXClient)&&(m_aClientSocket[j]!=INVALID_SOCKET);j++) ;
	int jErrorCode = send( m_aClientSocket[j], csText, sizeof(csText), NO_FLAGS); 
	OnServerBroadcast(csText);	
	for(int i=0;i<MAXClient;i++)
	{
		
		if (m_aClientSocket[i] != INVALID_SOCKET)
		{
			closesocket(m_aClientSocket[i]);
			m_aClientSocket[i] = INVALID_SOCKET;
		}
	}
	
	closesocket(m_pDoc->m_hServerSocket);	
	m_bServerIsOpen = FALSE;
    PrintString("\n==>>聊天室服务器关闭.\n");
	return;
}


void CServerView::OnServerOpen() 
{ 
	WSADATA wsaData;
	int iErrorCode;
	char chLocalInfo[64];
	
	if (WSAStartup(WINSOCK_VERSION, &wsaData))
	{
		MessageBeep(MB_ICONSTOP);
		MessageBox("Winsock could not be initialized!", AfxGetAppName(), MB_OK|MB_ICONSTOP);
		WSACleanup();
		return;
		  }
	else
		WSACleanup();
	
	if (gethostname(chLocalInfo, sizeof(chLocalInfo)))
	{
		ReportWinsockErr("\nCould not resolve local host!\nAre you on-line?\n");
		return;
	}
	CString csWinsockID = "\n==>>服务器已经开启,端口号: ";
	csWinsockID += itoa(m_pDoc->m_nServerPort, chLocalInfo, 10);
	csWinsockID += "\n";
	csWinsockID += wsaData.szDescription;
	csWinsockID += "\n";
	PrintString(csWinsockID);
	m_pDoc->m_hServerSocket = socket(PF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
	
	if (m_pDoc->m_hServerSocket == INVALID_SOCKET)
	 		{
		ReportWinsockErr("Could not create server socket.");
		return;
	 		}	
	m_pDoc->m_sockServerAddr.sin_family = AF_INET;
	m_pDoc->m_sockServerAddr.sin_addr.s_addr = INADDR_ANY;   
	m_pDoc->m_sockServerAddr.sin_port = htons(m_pDoc->m_nServerPort);
	if (bind(m_pDoc->m_hServerSocket, (LPSOCKADDR)&m_pDoc->m_sockServerAddr, sizeof(m_pDoc->m_sockServerAddr)) == SOCKET_ERROR)
	 		{
		ReportWinsockErr("Could not bind server socket.");
		return;
	 		}
	iErrorCode = WSAAsyncSelect(m_pDoc->m_hServerSocket, m_hWnd, WM_SERVER_ACCEPT, FD_ACCEPT);	
	if (iErrorCode == SOCKET_ERROR) 
	{
		ReportWinsockErr("WSAAsyncSelect failed on server socket.");
		return;
	}		
	if (listen(m_pDoc->m_hServerSocket, QUEUE_SIZE) == SOCKET_ERROR)
	 		{
		ReportWinsockErr("Server socket failed to listen.");
		m_pParentMenu->EnableMenuItem(ID_SERVER_OPEN, MF_ENABLED);
		return;
	 		}
	
	PrintString("==>>服务器套接字初始化完成 -- 等待连接.\n\n");
	
	m_bServerIsOpen = TRUE;
	return;	
}

LRESULT CServerView::OnClientRead(WPARAM wParam, LPARAM lParam)
{	
	int iBytesRead;
	int iBufferLength;
	int iEnd;
	int iSpaceRemaining;
	char chIncomingDataBuffer[1024];
	int i;	
	for(i=0;(i<MAXClient)&&(m_aClientSocket[i]!=wParam);i++)
	{
	}
	if(i==MAXClient) return 0L;
	
	iBufferLength = iSpaceRemaining = sizeof(chIncomingDataBuffer);
	iEnd = 0;
	iSpaceRemaining -= iEnd;
	iBytesRead = recv(m_aClientSocket[i], (LPSTR)(chIncomingDataBuffer+iEnd), iSpaceRemaining, NO_FLAGS);
	iEnd+=iBytesRead;
	if (iBytesRead == SOCKET_ERROR)
		ReportWinsockErr("OnClientRead recv reported a socket error.  ");
	chIncomingDataBuffer[iEnd] = '\0';	
	if (lstrlen(chIncomingDataBuffer) != 0)
	{
		PrintString(chIncomingDataBuffer);
		OnServerBroadcast(chIncomingDataBuffer);
	}
	else
		;
	// Since Windows send notification of FD_READ and FD_CLOSE,
	// assume the client has closed the connection if zero bytes
	// are received. The program uses a blocking socket, which means if the
	// connection were still open, recv() would wait for data.
	//OnClientClose();
	
	return(0L);
}

LRESULT CServerView::OnClientClose(WPARAM wParam, LPARAM lParam)
{
    int iErrorCode,i;
	
	if (WSAGETASYNCERROR(lParam)) 
		ReportWinsockErr("Error detected on entry into OnClientClose");
	
	for(i=0;(i<MAXClient)&&(m_aClientSocket[i]!=wParam);i++) ;
//	char chIncomingDataBuffer[10];
//    int iBytesRead = recv(m_aClientSocket[i], (LPSTR)(chIncomingDataBuffer), 10, NO_FLAGS);

	iErrorCode = closesocket(m_aClientSocket[i]);
	m_aClientSocket[i] = INVALID_SOCKET;
	
	if (iErrorCode == SOCKET_ERROR)
		ReportWinsockErr("Error closing client socket!");
	else
		PrintString("==>>客户端套接字成功关闭, 等待下一个客户到达!\n\n");
 //    	PrintString(chIncomingDataBuffer);
	return 0L;
}

LRESULT CServerView::OnClientReadClose(WPARAM wParam, LPARAM lParam)
{
	switch (WSAGETSELECTEVENT(lParam))
	{
	case FD_READ:
		OnClientRead(wParam,lParam);
		break;
	case FD_CLOSE:
		OnClientClose(wParam,lParam);
		break;
	}
	return 0L;
}

void CServerView::OnUpdateServerOpen(CCmdUI* pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bServerIsOpen ? FALSE:TRUE);	
}

void CServerView::OnUpdateServerClose(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bServerIsOpen ? TRUE : FALSE);	
}


LRESULT CServerView::OnServerBroadcast(char acSendBuff[])
{
	int i;
	for(i=0;i<MAXClient;i++)
	{
		if(m_aClientSocket[i]!=INVALID_SOCKET)
			int iErrorCode = send( m_aClientSocket[i], acSendBuff, lstrlen(acSendBuff), NO_FLAGS);
	}
	return 0L;
	
}

⌨️ 快捷键说明

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