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

📄 calldlg.cpp

📁 网络聊天工具原代码 VC源码(网络编程
💻 CPP
字号:
// CallDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Chat.h"
#include "CallDlg.h"
#include "ProxyAuthDlg.h"


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

#define ID_TIMER_CONNECT	1000
/////////////////////////////////////////////////////////////////////////////
// CCallDlg dialog


CCallDlg::CCallDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CCallDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CCallDlg)
	m_nPort = CHAT_PORT;
	m_szServer = _T("127.0.0.1");
	m_szCallTips = _T("等待");
	m_bUseProxy = FALSE;
	//}}AFX_DATA_INIT
	m_pClientThread = NULL;
	m_bState = CALL_ORIGIN;
	m_bMode = FALSE;		//不用代理
	m_lpReceiveBuffer = NULL;
}


void CCallDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCallDlg)
	DDX_Control(pDX, IDC_CALL_PROGRESS, m_ctrlProgress);
	DDX_Text(pDX, IDC_CALL_PORT, m_nPort);
	DDV_MinMaxUInt(pDX, m_nPort, 1, 65535);
	DDX_Text(pDX, IDC_CALL_SERVER, m_szServer);
	DDV_MaxChars(pDX, m_szServer, 128);
	DDX_Text(pDX, IDC_CALL_TIP, m_szCallTips);
	DDV_MaxChars(pDX, m_szCallTips, 10);
	DDX_Check(pDX, IDC_CALL_USEPROXY, m_bUseProxy);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CCallDlg, CDialog)
	//{{AFX_MSG_MAP(CCallDlg)
	ON_WM_TIMER()
	ON_MESSAGE( WM_CALL_TIMEOUT, OnCallTimeOut )
	ON_MESSAGE( WM_THREAD_QUIT, OnThreadQuit )
	ON_MESSAGE( WM_THREAD_DATA, OnThreadData )
	ON_MESSAGE( WM_THREAD_CONNECT, OnConnectOK )
	ON_MESSAGE( SOCKET_THREAD_CONNECT, OnThreadConnect )
	ON_MESSAGE( SOCKET_THREAD_RESOLVE, OnThreadResolve )
	ON_MESSAGE( SOCKET_THREAD_WRITE, OnThreadWrite )
	ON_MESSAGE( SOCKET_THREAD_TRANSFER, OnTransfer )
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCallDlg message handlers

BOOL CCallDlg::OnInitDialog() 
{

	
	m_hMainWnd = GetParent()->GetSafeHwnd();
	CDialog::OnInitDialog();	
	// TODO: Add extra initialization here
	m_ctrlProgress.ShowPercent( TRUE );
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CCallDlg::OnOK() 
{
	// TODO: Add extra validation here
	//进行连接, 如果一切正常,结束对话框,开始下棋


	UpdateData();


	m_bMode = m_bUseProxy;	

	if( m_bState == CALL_ORIGIN )
	{
		//用户点击连接
		//进行语法检查
		//以及是否采用代理
		if( m_szServer.IsEmpty() )
		{
			MessageBox( "主机不许为空,请输入主机名称或IP地址。", "错误", MB_OK|MB_ICONSTOP );
			return;
		}
		//创建线程
		ASSERT( m_pClientThread == NULL );
		m_pClientThread = new CClientThread(m_szServer, m_nPort, m_bUseProxy, GetSafeHwnd(), m_hMainWnd );
		if( m_pClientThread == NULL )
		{
			MessageBox("创建客户线程失败,请释放资源。", "错误", MB_OK|MB_ICONSTOP );
			return;
		}

		//创建成功,启动它
		m_pClientThread->CreateThread();
		//启动记数器
		SetTimer( ID_TIMER_CONNECT, 1000, NULL );
		//设置按钮为取消
		GetDlgItem( IDOK )->SetWindowText("取消" );
		m_ctrlProgress.SetRange( 0, confChat.nWaitTime );
		m_ctrlProgress.SetStep(1);
		m_ctrlProgress.SetPos( 0 );
		m_bState = CALL_CONNECTING;
	}
	else
	{
		//选择取消
		if( m_pClientThread )
		{
			m_pClientThread->KillThread();
			m_pClientThread = NULL;
		}
		m_bState = CALL_ORIGIN;
		KillTimer( ID_TIMER_CONNECT );
		CDialog::OnCancel();
	}
}

void CCallDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default

	if( nIDEvent == ID_TIMER_CONNECT )
	{
		//调整进度,并进行判断是否达到最大
		m_ctrlProgress.StepIt();

		if( (UINT)m_ctrlProgress.GetPos() == confChat.nWaitTime )
		{
			//ASSERT( m_bState == CALL_CONNECTING );
			//Stop it
			PostMessage( WM_CALL_TIMEOUT, 0, 0 );
		}
	}
	CDialog::OnTimer(nIDEvent);
}


void CCallDlg::OnCallTimeOut(WPARAM wParam, LPARAM lParam)
{
	//时间到

	if( m_pClientThread  )
	{
			m_pClientThread->KillThread();
			m_pClientThread = NULL;
	}
	if( m_bState != CALL_ORIGIN )
	{
			GetDlgItem(IDOK)->SetWindowText("连接");
			KillTimer( ID_TIMER_CONNECT );
			m_ctrlProgress.SetPos( 0 );
			m_bState = CALL_ORIGIN;
	}
}


void CCallDlg::OnCancel()
{

	if( m_bState != CALL_ORIGIN )
	{
		// 停止连接,退出
		if( m_pClientThread )
		{
			m_pClientThread->KillThread();
			m_pClientThread = NULL;
		}
	}
	m_bState = CALL_ORIGIN;
	CDialog::OnCancel();
}


void CCallDlg::OnThreadConnect( WPARAM wParam, LPARAM lParam )
{
	//收到连接消息
	// wParam是socket
	// HIWORD(lParam)是错误码
	// LOWORD(lParam)是消息,例如FD_CONNECT等
	int nError=HIWORD(lParam);

	//和Client线程保持同步	
	CSingleLock single( &g_cMutexClient );
	single.Lock();

	if( m_bState != CALL_CONNECTING ) return;
	if( m_pClientThread == NULL ) return;
	if( (SOCKET)wParam != m_pClientThread->GetSocket() ) return;

	//连接成功
	
	m_pClientThread->OnSocketConnect();

	switch( nError )
	{
	case 0:
		if( m_bMode == FALSE )
		{
				//已经连接好,不通过代理
				KillTimer( ID_TIMER_CONNECT );
				//等待线程发回 WM_THREAD_CONNECT消息
				return;
		}
		//采用Proxy,准备接收数据
		if( m_lpReceiveBuffer == NULL )
			m_lpReceiveBuffer = (LPBYTE)GlobalAlloc( GPTR, 
								MAX_PACKET_SIZE*2 );
		break;
	case WSAECONNREFUSED:
		//必须停止线程
		KillTimer( ID_TIMER_CONNECT );
		m_pClientThread->KillThread();
		m_pClientThread = NULL;
		MessageBox( "对方机器已经启动,但不能提供聊天服务。", "错误", MB_OK|MB_ICONSTOP );
		break;
	case WSAETIMEDOUT:
		KillTimer( ID_TIMER_CONNECT );
		m_pClientThread->KillThread();
		m_pClientThread = NULL;
		MessageBox( "您指定的主机无法连接,请重新输入。", "错误", MB_OK|MB_ICONSTOP );
		break;
	default: 
		CString szTemp;
		KillTimer( ID_TIMER_CONNECT );
		szTemp.Format( "SOCKET连接返回错误码:%d", nError );
		MessageBox( szTemp, "错误", MB_OK|MB_ICONSTOP );
		m_pClientThread->KillThread();
		m_pClientThread = NULL;
		break;
	}
}

void CCallDlg::OnThreadQuit( WPARAM wParam, LPARAM lParam )
{
	//收到退出消息
	int nError = LOWORD(lParam);

	//和Client线程保持同步	
	CSingleLock single( &g_cMutexClient );
	single.Lock();

	if( !wParam  )
	{
		//错误
		//ASSERT( m_pClientThread != NULL );
		KillTimer( ID_TIMER_CONNECT );
		if( m_pClientThread )
		{
			m_pClientThread->KillThread();
			m_pClientThread = NULL;
		}
		//m_pClientThread=NULL;
		GetDlgItem(IDOK)->SetWindowText("连接");
		m_ctrlProgress.SetPos(0);
		m_bState = CALL_ORIGIN;

		switch( nError )
		{
		case SOCKET_ERROR_REFUSE:
			MessageBox( "对方机器已经启动,但不能提供聊天服务。", "错误", MB_OK|MB_ICONSTOP );
			break;
		case SOCKET_ERROR_TIMEOUT:
			MessageBox( "您指定的主机无法连接,请重新输入。", "错误", MB_OK|MB_ICONSTOP );
			break;
		default: break;

		}

	}
}


void CCallDlg::OnThreadResolve(WPARAM wParam, LPARAM lParam )
{
	//得到解析消息

	if( m_pClientThread )
	{
		m_pClientThread->OnSocketConnect();
	}
}

void CCallDlg::OnThreadWrite( WPARAM wParam, LPARAM lParam )
{
		//发送连接请求,然后等候响应
		//读入数据进行分析后,在进行判断
		int bSuccess = (int)wParam;
		int nResult = (int)lParam;


		if( bSuccess == TRUE ) return;
		switch( nResult )
		{
		case SOCKET_ERROR_NOERROR:
			//发送成功,等候数据
			m_bState = CALL_WAITING;
			break;
		case SOCKET_ERROR_RESET:
			MessageBox( "传输通道重置,放弃连接。", "错误", MB_OK|MB_ICONSTOP );
			m_bState = CALL_CONNECTED;
			OnCancel();
			break;
		case SOCKET_ERROR_CLOSE:
			MessageBox("传输通道异常关闭,放弃连接。", "错误", MB_OK|MB_ICONSTOP );
			m_bState = CALL_CONNECTED;
			OnCancel();
			break;
		default:
			MessageBox("发送数据时发生错误。", "错误", MB_OK|MB_ICONSTOP );
			m_bState = CALL_CONNECTED;
			OnCancel();
			break;
		}	
}


void CCallDlg::OnTransfer(WPARAM wParam, LPARAM lParam )
{
	//收到FD_READ,FD_WRITE,FD_CLOSE的消息
	int nError = HIWORD(lParam);
	int nMessage=LOWORD(lParam);

	//和Client线程保持同步	
	CSingleLock single( &g_cMutexClient );
	single.Lock();

	if( m_pClientThread == NULL ) return;
	if( wParam == m_pClientThread->GetSocket() )
	{
		if( nError == 0 )
		{
			if( nMessage == FD_READ )
			{
				::PostThreadMessage( m_pClientThread->m_nThreadID,
					SOCKET_THREAD_READ, 0, 0 );
			}
			else if(nMessage == FD_WRITE )
			{
				::PostThreadMessage( m_pClientThread->m_nThreadID,
					SOCKET_THREAD_WRITE, 0, 0 );
			}
			else if( nMessage == FD_CLOSE )
			{
				//代理把网络关闭了
				if( m_bState == CALL_WAITING )
				{
					//还没读出数据就关了
					MessageBox("代理服务器关闭了网络连接,请重试。", "错误", MB_OK|MB_ICONSTOP );
				}
				if( m_pClientThread )
				{
					m_pClientThread->KillThread();
					m_pClientThread = NULL;
				}
				m_bState = CALL_ORIGIN;
				m_ctrlProgress.SetPos(0);
				KillTimer( ID_TIMER_CONNECT );
				GetDlgItem(IDOK)->SetWindowText("连接" );
			}
		}
	}
}


void CCallDlg::OnThreadData(WPARAM wParam, LPARAM lParam )
{
	//收到线程发来的数据读消息
	//处理代理服务器发来的响应
	int nBytes = (int)wParam;
	LPCTSTR lpTemp = (LPCTSTR)m_lpReceiveBuffer;
	CProxyAuthDlg	*pDlg = NULL;
	int nResult;
	CString szPassword;
	char	pBaseCode[512];

	//和Client线程保持同步	
	CSingleLock single( &g_cMutexClient );
	single.Lock();


	memcpy( m_lpReceiveBuffer, (LPBYTE)lParam, nBytes );

	//应该是 HTTP 200 OK就好了
	//可以考虑重新挂接消息

	////////////////////////////////////////////////
	/////////	HTTP 200
	/////////   已经连接好了
	////////////////////////////////////////////////
	if( strstr( lpTemp, "HTTP/1.0 200 ") != NULL )
	{
		if( confChat.bProxyUsable == PROXY_AUTH_UNSET )
		{
			confChat.bProxyUsable = PROXY_AUTH_NOPASS;
		}
		else	confChat.bProxyUsable = PROXY_AUTH_SETPASS;
		//本次连接就可以用

		//重新挂接网络消息
		if( m_pClientThread )
		{
			nResult = m_pClientThread->ChangeHandle();
			if( nResult == FALSE )
			{
				m_bState = CALL_DISCONNECT;
				MessageBox("不能和窗口绑定网络消息,请重新连接。", "错误", MB_OK|MB_ICONSTOP );
				OnCancel();
				return;
			}
			if( m_lpReceiveBuffer ) GlobalFree( m_lpReceiveBuffer );
			CDialog::OnOK();
		}
		return ;
	}

	////////////////////////////////////////////////
	/////////	HTTP 407
	/////////	要口令
	////////////////////////////////////////////////

	if( strstr( lpTemp, "HTTP/1.0 407 ") != NULL )
	{
		pDlg = new CProxyAuthDlg;
		if( pDlg != NULL )
		{
			//记忆上次输入的内容
			pDlg->m_szUserName = confChat.szProxyUser;
			pDlg->m_szProxy = confChat.szProxyIP;
			nResult = pDlg->DoModal();
			if( nResult != IDOK )
			{
				delete pDlg;
				return ;
			}
			//用局部变量保存起来
			confChat.szProxyUser = pDlg->m_szUserName;
			szPassword = pDlg->m_szPass;
			confChat.bProxyUsable = PROXY_AUTH_SETTING;
			delete pDlg;
		
			// 提交密码后,再次连接
			// 进行BASE64编码
			memset( pBaseCode ,0, 512 );
			HTTPAuth( (LPSTR)(LPCTSTR)confChat.szProxyUser, (LPSTR)(LPCTSTR)szPassword, pBaseCode );
			confChat.szProxyPass.Format( "%s", pBaseCode );
			// 再次连接远程服务
			//首先中断线程,再启动一个新的
			if( m_pClientThread != NULL )
			{
				m_pClientThread->KillThread();
				m_pClientThread = NULL;
			}

			m_pClientThread = new CClientThread(m_szServer, m_nPort, m_bUseProxy, GetSafeHwnd(), m_hMainWnd );
			if( m_pClientThread == NULL )
			{
				MessageBox("创建客户线程失败,请释放资源。", "错误", MB_OK|MB_ICONSTOP );
				return;
			}

			//创建成功,启动它
			m_pClientThread->CreateThread();
			m_bState = CALL_CONNECTING;
			//重新记数
			KillTimer( ID_TIMER_CONNECT );
			m_ctrlProgress.SetPos(0);
			SetTimer( ID_TIMER_CONNECT, 1000, NULL );
			GetDlgItem( IDOK )->SetWindowText("取消");
			return;
		}
		OnCancel();
		return;
	}
	
	////////////////////////////////////////////////
	/////////	HTTP 403 
	/////////	被禁止
	////////////////////////////////////////////////
	if( strstr( lpTemp, "HTTP/1.0 403 ") != NULL )
	{
		MessageBox("您的连接请求被代理服务器拒绝,请重新连接。", "错误", MB_OK|MB_ICONSTOP );
		m_bState = CALL_CONNECTING;
		OnCancel();
		return;
	}
	//MessageBox("您的连接请求代理服务器认为无效,请联系网络管理员。", "错误", MB_OK|MB_ICONSTOP );
	//m_bState = CALL_CONNECTING;
	//OnCancel();
	//return;
}

void CCallDlg::HTTPAuth(char *uid, char *pass, char *outbuf)
{
	char temp[512];
	char buf[256];
	int ret = -1;

	memset(buf,0,256);
	memset(temp,0,512);

	memcpy(buf,uid,strlen(uid));
	memcpy(buf+strlen(uid),":",1);
	memcpy(buf+strlen(uid)+1,pass,strlen(pass));

	Base64Code(buf,temp);
	strcpy(outbuf,HTTP_AUTH_HEAD);
	strcat(outbuf+strlen(HTTP_AUTH_HEAD),temp);
	ret = strlen(outbuf) ;
}

void CCallDlg::Base64Code(char *inbuf, char *outbuf)
{
	int ret = -1 ;
	int i = 0 ;
	int remain;
	int oneout;
	int num;
	int c = 0 ;
	int now;
	char CODETABLE[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	
	if ( *inbuf <= 0 )
	{
		goto end;
	}
	num = 8 ;
	remain = *inbuf;
	oneout = 0 ;
	now = 0 ;
	while ( 1 )
	{
		while ( num >= 6 )
		{
			oneout = ( remain >> (num-6) ) & 0x3f ;
			memcpy( outbuf+now, &CODETABLE[oneout] , 1 );
			now++;
			num -=6;
			if ( num == 2 )
				c = 0x0300;
			else
				if ( num == 4 )
					c = 0x0f00;
				else
					if ( num == 6 )
						c = 0x3f00;
					else
						c = 0x0000;
			if ( num != 6 )
				remain = ( remain <<8 ) & c ;
		}
		if ( *(++inbuf)==NULL )
			break;
		if ( num == 2 )
			c = 0x03ff;
		else
			if ( num == 4 )
				c = 0x0fff;
			else
				c = 0x00ff;
		remain = ( remain | ( *inbuf & 0x00ff ) ) & c ;
		num+=8;
	}
	if  ( ( num < 6 ) && ( num != 0 ) ) 
	{
		remain = remain >> 8 ;
		remain = ( remain <<( 6 - num )) & 0x00003f;
		memcpy( outbuf+now, &CODETABLE[remain] , 1 ) ;
		now++;
		memcpy( outbuf+now, "==" ,  6/2 - num/2 ) ;
		now +=6/2 - num/2;
	}
	ret = 0 ;
end:
	return;
}


void CCallDlg::OnConnectOK(WPARAM wParam, LPARAM lParam)
{

	//和Client线程保持同步	
	CSingleLock single( &g_cMutexClient );
	single.Lock();

	if( m_bState != CALL_CONNECTING ) return;
	m_bState = CALL_CONNECTED;
	//如果有Proxy,连通不算真正能用
	if( m_bMode == TRUE ) return;
	//已经收到连接好的消息
	if( m_lpReceiveBuffer != NULL )
	{
		GlobalFree( m_lpReceiveBuffer );
		m_lpReceiveBuffer = NULL;
	}
	m_bState = CALL_CONNECTED;

	CDialog::OnOK();
}

⌨️ 快捷键说明

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