📄 chatdlg.cpp
字号:
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 + -