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

📄 tcpsocket.cpp

📁 网络聊天工具原代码 VC源码(网络编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// TCPSocket.cpp : implementation file
//

#include "stdafx.h"
#include "Chat.h"
#include "TCPSocket.h"

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

/////////////////////////////////////////////////////////////////////////////
// CTCPSocket

/*

		对TCP进行socket封装,回调机制采用WSAAsyncSelect
		由窗口->线程->网络->窗口
 */

CTCPSocket::CTCPSocket()
{
	m_hMainWnd = NULL;
	m_bState = SOCKET_ORIGIN;
	m_bSocketType = SOCKET_CLIENT;
	m_nErrorCode = SOCKET_ERROR_NOERROR;
	m_TCP_s = INVALID_SOCKET;
	m_hWaitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
	m_lpReceiveBuffer = NULL;
	m_lpSendBuffer = NULL;
	m_nBegin = 0;
	m_nEnd = 0;
	m_szHost = _T("");
}

CTCPSocket::~CTCPSocket()
{
	CloseHandle( m_hWaitEvent );
	Close();
	if( m_lpReceiveBuffer ) 
	{ 
			GlobalFree( m_lpReceiveBuffer );
			m_lpReceiveBuffer = NULL;
	}
	if( m_lpSendBuffer ) 
	{
			GlobalFree( m_lpSendBuffer );
			m_lpSendBuffer = NULL;
	}
}



/////////////////////////////////////////////////////////////////////////////
// CTCPSocket member functions

int CTCPSocket::GetLastError()
{
	//应该综合考虑WSAGetLastError和m_nErrorCode;
	return	m_nErrorCode;
}

BOOL CTCPSocket::CreateClient(CString szHost, int nPort, BOOL bUseProxy, HWND hWnd, HWND hFinalWnd)
{
	//创建客户端,由线程外围调用。
	//hWnd是主消息窗口句柄


	int		nResult;
	BOOL	bTemp;
	CString szTemp;

	/////  m_hWnd是用来挂接连接好后的
	/////  SOCKET_THREAD_TRANSFER消息
	m_hFinalWnd = hFinalWnd;
	m_bUseProxy = bUseProxy;

	////////////////////////////////////////////////////
	//Step 0 
	////////////////////////////////////////////////////
	ASSERT( m_TCP_s == INVALID_SOCKET );
	
	m_hMainWnd = hWnd;

	m_lpReceiveBuffer = (LPBYTE)GlobalAlloc( GPTR, MAX_PACKET_SIZE*4 );
	if( !m_lpReceiveBuffer )
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}
	m_lpSendBuffer = (LPBYTE)GlobalAlloc( GPTR, MAX_PACKET_SIZE+1 );
	if( !m_lpSendBuffer )
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}


	////////////////////////////////////////////////////

	////////////////////////////////////////////////////
	//Step 1 
	//分析主机名称
	//并试图解析
	////////////////////////////////////////////////////
	m_bState = SOCKET_GETNAME;

	//保存用户要连接的主机名称
	m_szHost = szHost;
	m_nPort = nPort;

	// 如果用代理,必须首先连接代理
	if( bUseProxy ) szTemp = confChat.szProxyIP;
	else			szTemp = szHost;

	//去掉左右两边空格
	szTemp.TrimLeft();
	szTemp.TrimRight();

	//首先解析域名,如果已经是ip直接计算得到ipServer
	bTemp = GetHostIP( szTemp );
	//如果出现错误
	if( !bTemp ) 
	{
		m_nErrorCode = SOCKET_ERROR_HOSTNAME;
		return FALSE;
	}
	////////////////////////////////////////////////////

	////////////////////////////////////////////////////
	////  Step 2 连接主机
	////  可能被拒绝或者TIMEOUT
	////////////////////////////////////////////////////
	
	///////创建SOCKET
	//////---------------------------
	m_TCP_s = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
	if( m_TCP_s == INVALID_SOCKET )
	{
		////////////创建失败
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}

	//////设置连接方式
	struct	sockaddr_in dummy;
	
	dummy.sin_addr = ipServer;
	dummy.sin_family = AF_INET;
	if( bUseProxy ) dummy.sin_port = htons( confChat.nProxyPort );
	else			dummy.sin_port = htons( nPort );

	//////设置FD_CONNECT消息
	nResult = WSAAsyncSelect(
					m_TCP_s, 
					m_hMainWnd, 
					SOCKET_THREAD_CONNECT, 
					FD_CONNECT|FD_WRITE
				);
	if( nResult == SOCKET_ERROR )
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}

	///////设置消息成功,开始连接 
	nResult = connect( 
					m_TCP_s, 
					(LPSOCKADDR)&dummy, 
					sizeof(dummy) 
				);
	if( nResult != SOCKET_ERROR )
	{
		m_nErrorCode = SOCKET_ERROR_CONNECT;
		return FALSE;
	}
	///////检查异步是否正确设置
	nResult = WSAGetLastError();
	if( nResult != WSAEWOULDBLOCK )
	{
		m_nErrorCode = SOCKET_ERROR_CONNECT;
		return FALSE;
	}

	////////已经设置好异步方式连接,开始等待
	m_bState = SOCKET_CONNECTING;

	//等待的时间比配置的多一倍
	m_bCancelJob = FALSE;
	ResetEvent( m_hWaitEvent );
	nResult = WaitForSingleObject( m_hWaitEvent, confChat.nWaitTime*2000 );
	ASSERT( nResult != WAIT_TIMEOUT );
	
	//////有可能用户取消或者,时间到
	if( m_bCancelJob )
	{
		m_nErrorCode = SOCKET_ERROR_CANCEL;
		return FALSE;
	}

	nResult = WSAGetLastError();
	if( nResult&&(nResult!=WSAEWOULDBLOCK) )
	{
		//连接出错
		switch( nResult )
		{
		case WSAECONNREFUSED:
			//被拒绝
			m_nErrorCode = SOCKET_ERROR_REFUSE;
			break;
		case WSAETIMEDOUT:
			m_nErrorCode = SOCKET_ERROR_TIMEOUT;
			break;
		default:
			m_nErrorCode = SOCKET_ERROR_UNKNOWN;
			break;
		}
		return FALSE;
	}
	////////在规定时间内连接成功
	//////重新设置异步消息

	WSAAsyncSelect( m_TCP_s , m_hMainWnd, 0, 0 );

	if( m_bUseProxy == FALSE )m_hMainWnd = m_hFinalWnd;

	nResult = WSAAsyncSelect( 
					m_TCP_s, 
					m_hMainWnd, 
					SOCKET_THREAD_TRANSFER, 
					FD_READ|FD_WRITE|FD_CLOSE
				);
	if( nResult == SOCKET_ERROR )
	{
		m_nErrorCode = SOCKET_ERROR_CONNECT;
		return FALSE;
	}  

	////////////到这里,连接已经全部完成
	////////////可以开始读写数据了

	//如果使用代理,发出连接请求,暂时不支持

	//直接发出第一个数据包
	if( m_bUseProxy )
	{
		nResult = SendFirstPacket();
		::PostMessage( m_hMainWnd, SOCKET_THREAD_WRITE,
			(nResult == 0), nResult );
	}


	m_bState = SOCKET_CONNECTED;
	m_bSocketType = SOCKET_CLIENT;
	m_bCanWrite = TRUE;

	return TRUE;
}

BOOL CTCPSocket::CreateServer(int nPort, HWND hWnd)
{
	//创建服务器,由线程外围调用。
	//hWnd是主消息窗口句柄
	int nResult;
	SOCKADDR_IN	addrLocal;

	////////////////////////////////////////////////////
	//Step 0 
	////////////////////////////////////////////////////
	ASSERT( m_TCP_s == INVALID_SOCKET );
	
	m_hMainWnd = hWnd;
	m_nPort = nPort;

	////////////////////////////////////////////////////
	///Step 1 创建SOCKET
	////////////////////////////////////

	
	m_TCP_s =  socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
	if( m_TCP_s == INVALID_SOCKET )
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}

	m_bState = SOCKET_INIT;

	////////////////////////////////////////////////////
	///Step 2 设置地址
	////////////////////////////////////

	addrLocal.sin_family = AF_INET;
	addrLocal.sin_port = htons( m_nPort );
	addrLocal.sin_addr.s_addr = INADDR_ANY;

	////////////////////////////////////////////////////
	///Step 3 绑定端口
	////////////////////////////////////

	nResult = bind( m_TCP_s,(LPSOCKADDR)&addrLocal,sizeof(addrLocal) );
	if( nResult == SOCKET_ERROR )     
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}

	////////////////////////////////////////////////////
	///Step 4 听端口
	////////////////////////////////////

	nResult = listen( m_TCP_s, SOMAXCONN );
	if( nResult == SOCKET_ERROR )
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}

	////////////////////////////////////////////////////
	///Step 5 异步等待连接
	////////////////////////////////////

	if( WSAAsyncSelect ( m_TCP_s, m_hMainWnd, SOCKET_THREAD_ACCEPT, FD_ACCEPT ) == SOCKET_ERROR )
	{
		m_nErrorCode = SOCKET_ERROR_CREATE;
		return FALSE;
	}

	m_bState = SOCKET_ACCEPTING;
	m_bSocketType = SOCKET_SERVER_LISTEN;
	return TRUE;
}




void CTCPSocket::Close()
{
	if( m_TCP_s != INVALID_SOCKET ) 
	{
		if( (m_bState == SOCKET_ACCEPTING)||
			(m_bState == SOCKET_CONNECTED) )
		{
			WSAAsyncSelect( m_TCP_s, m_hMainWnd, 0, 0 );
		}
		closesocket(m_TCP_s);
		m_TCP_s = INVALID_SOCKET;
	}
}

BOOL CTCPSocket::GetHostIP(CString szHost)
{
	int		iLen;

⌨️ 快捷键说明

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