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