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

📄 chatdlg.cpp

📁 网络聊天工具原代码 VC源码(网络编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		time_t t_cur = cCurTime.GetTime();
		CTimeSpan cSub(t_cur-t_start);
		CString szTemp = cSub.Format("%H:%M:%S" );
		GetDlgItem( IDC_TIME)->SetWindowText( szTemp );
	}
	CDialog::OnTimer(nIDEvent);
}

void CChatDlg::SendCommand(int nAct, int nBytes, LPCTSTR lpszChat)
{
	//nAct是动作类型
	int nLen;

	if( m_bType == IAM_NULL ) return;
	if( m_bCanWrite == FALSE ) return;
	UpdateData();

	switch( nAct )
	{
	case CHAT_ACT_SEND_NAME:
		//发送姓名
		m_lpSendBuffer[0] = (BYTE)nAct;
		nLen = confChat.szUserName.GetLength();
		m_lpSendBuffer[1] = (BYTE)(nLen+2);
		memcpy( m_lpSendBuffer+2, (LPCTSTR)confChat.szUserName, nLen );
		nLen+=2;
		break;
	case CHAT_ACT_ASK_SEND:
		//发送聊天内容
		nLen = m_szChatSend.GetLength();
		if( nLen == 0 ) {return;}

		m_lpSendBuffer[0] = (BYTE)nAct;		
		m_lpSendBuffer[1] = (BYTE)(nLen+2 );
		memcpy( m_lpSendBuffer+2, (LPCTSTR)m_szChatSend, nLen );
		nLen+=2;
		break;
	case CHAT_ACT_QUIT:
	case CHAT_ACT_NULL:
	case CHAT_ACT_AGREE_TEST:
	case CHAT_ACT_ASK_TEST:
	case CHAT_ACT_AGREE_SEND:
	case CHAT_ACT_BUSY:
		m_lpSendBuffer[0] = (BYTE)nAct;
		nLen = 1;
		break;
	default: return;
	}

	if( nLen == 0 ) return;
	if( m_pClientThread )
	{
		PostThreadMessage( 
				m_pClientThread->m_nThreadID,
				WM_THREAD_DATA,
				nLen,
				(LPARAM)m_lpSendBuffer
			);
		m_bCanWrite = FALSE;
	}
	else
	{
		if( m_pServerThread )
		{
			PostThreadMessage( 
				m_pServerThread->m_nThreadID,
				WM_THREAD_DATA,
				nLen,
				(LPARAM)m_lpSendBuffer
			);
			m_bCanWrite = FALSE;
		}
	}
}


void CChatDlg::OnTransfer( WPARAM wParam, LPARAM lParam )
{
	SOCKET s=(SOCKET)wParam;
	int nError = HIWORD(lParam);
	int nMessage = LOWORD(lParam);
	int nSendMessage;

	if( m_bType == IAM_NULL ) return;

	if( m_bType == IAM_CLIENT)
	{
		CSingleLock single(&g_cMutexClient );
		single.Lock();
	}
	else 
	{
		CSingleLock single(&g_cMutexServer );
		single.Lock();
	}

	

	if( s == INVALID_SOCKET ) return;

	if( m_bType == IAM_CLIENT )
	{
		if( m_pClientThread == NULL ) return;
		if( s != m_pClientThread->GetSocket() ) return;
		//客户端的消息
		

		if( nError == 0 )
		{
			if( nMessage == FD_READ ) nSendMessage = SOCKET_THREAD_READ;
			else if( nMessage == FD_WRITE ) 
			{
				nSendMessage = SOCKET_THREAD_WRITE;
				m_bCanWrite = TRUE;
			}
			else if (nMessage == FD_CLOSE ) 
			{
				if( m_bType==IAM_CLIENT )
				{
					//正在下时,网络断掉,应该考虑如何恢复连接
					MessageBox("客户模块发现网络中断,请重新连接。", "错误", MB_OK|MB_ICONSTOP );
				}
				nSendMessage = SOCKET_THREAD_CLOSE;
			}
			else 
			{
				return;
			}
			PostThreadMessage( 
					m_pClientThread->m_nThreadID,
					nSendMessage, 0, 0 );
		}
		//出现错误,根据错误,通知线程
		return;
	}

	if( m_pServerThread == NULL )  return;

	if( s == m_pServerThread->GetSocket() )
	{
		if( nError == 0 )
		{
			if( nMessage == FD_READ ) nSendMessage = SOCKET_THREAD_READ;
			else if( nMessage == FD_WRITE )
			{
				m_bCanWrite = TRUE;
				nSendMessage = SOCKET_THREAD_WRITE;
			}
			else if (nMessage == FD_CLOSE ) 
			{
				if( (m_bType==IAM_SERVER) && (m_bState==MY_ORIGIN) )
				{
					
					MessageBox("服务模块发现网络中断,请重新连接。", "错误", MB_OK|MB_ICONSTOP );
				}
				nSendMessage = SOCKET_THREAD_CLOSE;
				//自行设置
				
				GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
				GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
				GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
				GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
				GetDlgItem(IDC_FROMIP )->SetWindowText( _T("") );
				GetDlgItem(IDC_YOUNAME)->SetWindowText( _T("") );
				GetDlgItem(IDC_TIME)->SetWindowText( _T("") );
				
				m_bState = MY_ORIGIN;
				m_bType = IAM_NULL;
				m_bHaveGotName = FALSE;

				KillTimer( ID_TIMER_CHAT );
			}
			else 
			{
				return;
			}
			PostThreadMessage( 
					m_pServerThread->m_nThreadID,
					nSendMessage, 0, 0 );
		}
		//出现错误,根据错误,通知线程
	}

}


void CChatDlg::OnClientAccept( WPARAM wParam, LPARAM lParam )
{
	SOCKET s=(SOCKET)wParam;
	int nError = HIWORD(lParam);
	int nMessage = LOWORD(lParam);

	//和Server线程保持同步	
	CSingleLock single( &g_cMutexServer );
	single.Lock();
	
	
	if( s == INVALID_SOCKET ) return;
	if( m_pServerThread == NULL ) return;
	if(s != m_pServerThread->GetListenSocket() )return;
	if( nMessage == FD_ACCEPT )
	{
		//收到有效的连接消息
		if( nError == 0 )
		{
			//通知线程接收连接
			if( m_pServerThread )
			{
				if( m_bState == IAM_NULL )PostThreadMessage( m_pServerThread->m_nThreadID, SOCKET_THREAD_CONNECT, TRUE, 0 );
				else PostThreadMessage( m_pServerThread->m_nThreadID, SOCKET_THREAD_CONNECT, FALSE, 0 );


				GetDlgItem( IDC_CONNECT)->SetWindowText("测试" );				
				GetDlgItem(IDC_DISCONNECT)->EnableWindow( TRUE );				
				GetDlgItem( IDC_CHAT_LIST )->SetWindowText(_T("") );
				m_bState = MY_CONNECTED;				
				m_bType = IAM_SERVER;
				m_bHaveGotName = FALSE;
			}
			return;
		}
	}
}

void CChatDlg::OnThreadQuit( WPARAM wParam, LPARAM lParam )
{
	int nError = LOWORD(lParam);
	BOOL IsServer = HIWORD(lParam);
	int  nResult;

	

	if( !wParam )
	{
		//出现错误
		if( IsServer )
		{
			CSingleLock single( &g_cMutexServer );
			single.Lock();
			//如果Server发出退出指令
			ASSERT( m_pServerThread != NULL );
			m_pServerThread->KillThread();
			m_pServerThread = NULL;
			CString szError;
			szError.Format( "服务模块出错,返回值为%d。注意不要启动两次Chat程序。是否重新启动?", nError );
			nResult = MessageBox( szError, "错误", MB_OKCANCEL|MB_ICONINFORMATION );
			if( nResult == IDOK )
			{
				m_pServerThread = new CServerThread( GetSafeHwnd(), confChat.nServicePort );
				if( m_pServerThread == NULL )
				{
					MessageBox("无法启动服务线程,请释放资源。", "错误", MB_OK|MB_ICONSTOP );
					return;
				}
				m_pServerThread->CreateThread();
				SetWindowText( "Net Chat v0.1" );
				return;
			}
			SetWindowText( "Net Chat v0.1 ----服务没有启动" );
			return;
		}
		//客户端线程发出的退出请求
		CSingleLock single1( &g_cMutexClient );
		single1.Lock();
		ASSERT( m_pClientThread != NULL );
		m_pClientThread->KillThread();
		m_pClientThread = NULL;


		GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
		GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
		GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
		GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
		GetDlgItem(IDC_FROMIP )->SetWindowText( _T("") );
		GetDlgItem(IDC_YOUNAME)->SetWindowText( _T("") );
		GetDlgItem(IDC_TIME)->SetWindowText( _T("") );
		

		m_bState = MY_ORIGIN;
		m_bType = IAM_NULL;
		m_bHaveGotName = FALSE;

		KillTimer( ID_TIMER_SENDPROXY );
		KillTimer( ID_TIMER_CHAT );

	}
}



void CChatDlg::OnThreadData(WPARAM wParam, LPARAM lParam)
{
	//收到线程发来的数据
	//分析生成命令
	//wParam是字节数
	//lParam是指针
	int nBytes = wParam;
	LPBYTE lpBuf = (LPBYTE)lParam;
	//由数据函数负责处理
	UpdateData();

	if( m_bType == IAM_CLIENT)
	{
		CSingleLock single(&g_cMutexClient );
		single.Lock();
	}
	else 
	{
		CSingleLock single(&g_cMutexServer );
		single.Lock();
	}

	memcpy( m_lpReceiveBuffer, lpBuf, nBytes );
	AnalyzeData( m_lpReceiveBuffer, nBytes );
}



void CChatDlg::OnThreadWrite(WPARAM wParam, LPARAM lParam)
{
	//接受写入数据的情况
	int nResult=(int)lParam;
	int bSuccess = (int)wParam;


	if( m_bType == IAM_NULL ) return;

	if( m_bType == IAM_CLIENT)
	{
		CSingleLock single(&g_cMutexClient );
		single.Lock();
	}
	else 
	{
		CSingleLock single(&g_cMutexServer );
		single.Lock();
	}

	if( bSuccess ) { m_bCanWrite = TRUE; }
	else
	{
			switch( nResult )
			{
			case SOCKET_ERROR_BLOCK:
				//希望采用异步工作模式
				m_bCanWrite = FALSE;
				break;
			case SOCKET_ERROR_CLOSE:
				
				//出现异常关闭,很少出现的
				//处理方法和正常关闭一样
				if( m_pClientThread ) 
				{
					m_pClientThread->KillThread();
					m_pClientThread = NULL;
				}
				else
				{
					::PostThreadMessage( m_pServerThread->m_nThreadID,
					SOCKET_THREAD_SHUT, 0, 0 );
				}

				GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
				GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
				GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
				GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
				GetDlgItem(IDC_FROMIP )->SetWindowText( _T("") );
				GetDlgItem(IDC_YOUNAME)->SetWindowText( _T("") );
				GetDlgItem(IDC_TIME)->SetWindowText( _T("") );

				m_bState = MY_ORIGIN;
				m_bType = IAM_NULL;
				m_bHaveGotName = FALSE;
				m_bCanWrite = FALSE;
				KillTimer( ID_TIMER_CHAT );

				MessageBox( "写入数据时发现网络已经关闭,聊天自动结束。", "错误", MB_OK|MB_ICONSTOP );
				break;
			case SOCKET_ERROR_RESET:
				
				//出现异常关闭,很少出现的
				//处理方法和正常关闭一样
				if( m_pClientThread ) 
				{
					m_pClientThread->KillThread();
					m_pClientThread = NULL;
				}
				else
				{
					::PostThreadMessage( m_pServerThread->m_nThreadID,
					SOCKET_THREAD_SHUT, 0, 0 );
				}

				
				GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
				GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
				GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
				GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
				GetDlgItem(IDC_FROMIP )->SetWindowText( _T("") );
				GetDlgItem(IDC_YOUNAME)->SetWindowText( _T("") );
				GetDlgItem(IDC_TIME)->SetWindowText( _T("") );

				m_bState = MY_ORIGIN;
				m_bType = IAM_NULL;
				m_bHaveGotName = FALSE;
				m_bCanWrite = FALSE;
				KillTimer( ID_TIMER_CHAT );

				

				MessageBox( "写入数据时发现网络虚电路重置,游戏自动结束。", "错误", MB_OK|MB_ICONSTOP );

				break;
			default: 
				//提示错误码
				
				//出现异常关闭,很少出现的
				//处理方法和正常关闭一样
				if( m_pClientThread ) 
				{
					m_pClientThread->KillThread();
					m_pClientThread = NULL;
				}
				else
				{
					::PostThreadMessage( m_pServerThread->m_nThreadID,
					SOCKET_THREAD_SHUT, 0, 0 );
				}

				GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
				GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
				GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
				GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
				GetDlgItem(IDC_FROMIP )->SetWindowText( _T("") );
				GetDlgItem(IDC_YOUNAME)->SetWindowText( _T("") );
				GetDlgItem(IDC_TIME)->SetWindowText( _T("") );


				m_bState = MY_ORIGIN;
				m_bType = IAM_NULL;
				m_bHaveGotName = FALSE;
				m_bCanWrite = FALSE;
				KillTimer( ID_TIMER_CHAT );


				CString szTemp;
				szTemp.Format("写入数据时出现错误,错误码为%d。游戏自动结束", nResult );
				MessageBox( szTemp, "错误", MB_OK|MB_ICONSTOP );
				break;
			}
	}
}

void CChatDlg::AnalyzeData(LPBYTE lpBuffer, int nBytes)
{
	int nResult = nBytes;
	///分析数据
	int nAct;
	char temp[256];
	CString szTemp;

	if( lpBuffer == NULL ) return;
	if( nBytes == 0 ) return;
	if( m_bType == IAM_NULL ) return;

	UpdateData();

	//第一个字节是命令
	nAct = lpBuffer[0];
	switch( nAct )
	{
	case CHAT_ACT_NULL:
		if( m_bType == IAM_SERVER )
		{
			SendCommand( CHAT_ACT_NULL );
		}
		break;
	case CHAT_ACT_SEND_NAME:
		if( lpBuffer[1] != nBytes ) return;
		memcpy( temp, lpBuffer+2, nBytes-2 );
		temp[nBytes-2] = '\0';
		szTemp = _T(temp );
		m_ctrlChat.SetUser( confChat.szUserName, szTemp );
		GetDlgItem(IDC_CHAT )->SetWindowText( _T("") );
		GetDlgItem( IDC_CHAT )->EnableWindow(TRUE );
		GetDlgItem( IDC_SEND )->EnableWindow(TRUE);
		//修改连接
		if( m_bType == IAM_SERVER )	
			 GetDlgItem( IDC_FROMIP)->SetWindowText(m_pServerThread->GetHost() );
		else    
			 GetDlgItem( IDC_FROMIP)->SetWindowText(m_pClientThread->GetHost() );
		GetDlgItem( IDC_YOUNAME )->SetWindowText( szTemp );
		//启动记时器
		if( m_bHaveGotName == FALSE  )
		{
			if( m_bType == IAM_SERVER )
			{
				SendCommand( CHAT_ACT_SEND_NAME );			
			}
			//Start timer
			SetTimer( ID_TIMER_CHAT, 1000, NULL );
			CTime cStartTime = CTime::GetCurrentTime();
			t_start = cStartTime.GetTime();
		}
		m_bHaveGotName = TRUE;
		break;
	case CHAT_ACT_ASK_SEND:
		if( lpBuffer[1] != nBytes ) return;
		memcpy( temp, lpBuffer+2, nBytes-2 );
		temp[nBytes-2] = '\0';
		m_ctrlChat.PostChat( (LPSTR)temp, FALSE );
		SendCommand( CHAT_ACT_AGREE_SEND );
		break;
	case CHAT_ACT_AGREE_SEND:
		if( m_bState != MY_ASKING ) return;
		m_bState = MY_CONNECTED;
		GetDlgItem(IDC_SEND )->EnableWindow( TRUE );
		break;
	case CHAT_ACT_ASK_TEST:
		SendCommand( CHAT_ACT_AGREE_TEST );
		break;
	case CHAT_ACT_AGREE_TEST:
		if( m_bState != MY_ASKING ) return;
		m_bState = MY_CONNECTED;
		GetDlgItem(IDC_CONNECT )->EnableWindow( TRUE );
		MessageBox("网络畅通,请继续聊天。" , "提示", MB_OK|MB_ICONINFORMATION);
		break;
	case CHAT_ACT_BUSY:
		//if( m_bState != MY_ASKING ) return;
		if( m_pClientThread ) 
		{
			m_pClientThread->KillThread();
			m_pClientThread = NULL;
		}
		GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
		GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
		GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
		GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
		m_bState = MY_ORIGIN;
		m_bType = IAM_NULL;
		m_bHaveGotName = FALSE;
		MessageBox( "对方正忙,请以后再连接。", "提示", MB_OK|MB_ICONSTOP );
		break;
	case CHAT_ACT_QUIT:
		if( m_pClientThread ) 
		{
			m_pClientThread->KillThread();
			m_pClientThread = NULL;
		}
		else
		{
			::PostThreadMessage( m_pServerThread->m_nThreadID,
					SOCKET_THREAD_SHUT, 0, 0 );
		}

		GetDlgItem(IDC_DISCONNECT)->EnableWindow( FALSE );
		GetDlgItem(IDC_CHAT )->EnableWindow(FALSE );
		GetDlgItem(IDC_SEND )->EnableWindow(FALSE );	
		GetDlgItem(IDC_CONNECT)->SetWindowText("呼叫");
		GetDlgItem(IDC_FROMIP )->SetWindowText( _T("") );
		GetDlgItem(IDC_YOUNAME)->SetWindowText( _T("") );
		GetDlgItem(IDC_TIME)->SetWindowText( _T("") );
		m_bState = MY_ORIGIN;
		m_bType = IAM_NULL;
		m_bHaveGotName = FALSE;
		KillTimer( ID_TIMER_CHAT );

		MessageBox("对方退出了,聊天自动结束。", "提示", MB_OK );
		break;	
	default: break;
	}
}

void CChatDlg::OnFileAbout() 
{
	// TODO: Add your command handler code here
	CAboutDlg dlgAbout;
	dlgAbout.DoModal();	
}

⌨️ 快捷键说明

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