449 lines
14 KiB
C++
449 lines
14 KiB
C++
// TcpClient.cpp: implementation of the CTcpClient class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "GeoMative.h"
|
|
#include "TcpClient.h"
|
|
#include "FileOperTools.h"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#define MODULE_NAME "TcpClient"
|
|
#define SHUT_RDWR 2
|
|
#define MAX_SKIP_BYTE 60
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CTcpClient::CTcpClient()
|
|
{
|
|
m_strIP = _T("");
|
|
m_wPort = 0;
|
|
m_sockClient = INVALID_SOCKET;
|
|
m_iRcvBuf = m_iSndBuf = 64*1024;
|
|
m_bIsConnect = false;
|
|
m_pClearRcvBuf = NULL;
|
|
|
|
}
|
|
|
|
CTcpClient::~CTcpClient()
|
|
{
|
|
closesocket(m_sockClient);
|
|
if (m_pClearRcvBuf)
|
|
{
|
|
delete []m_pClearRcvBuf;
|
|
}
|
|
|
|
}
|
|
|
|
//默认为套接字的属性为阻塞的
|
|
bool CTcpClient::InitailTcp()
|
|
{
|
|
if (INVALID_SOCKET != m_sockClient)
|
|
{
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
AfxMessageBox(_T("需要初始化的套接字不为空"));
|
|
else
|
|
MessageBoxEx(NULL, _T("The socket that needs to be initialized is not empty"), STRING_MESSAGEBOXEX_TITLE, MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
return false;
|
|
}
|
|
m_sockClient = socket(AF_INET, SOCK_STREAM, 0);
|
|
CString strLog = _T("");
|
|
if (INVALID_SOCKET == m_sockClient)
|
|
{
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
AfxMessageBox(_T("创建套接字失败"));
|
|
else
|
|
MessageBoxEx(NULL, _T("Create socket failed."), STRING_MESSAGEBOXEX_TITLE, MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
return false;
|
|
}
|
|
//这里不需要优雅关闭,最多进行重传
|
|
struct linger stLinger;
|
|
stLinger.l_onoff = 0;
|
|
stLinger.l_linger = 0;
|
|
if (SOCKET_ERROR == setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&stLinger, sizeof(stLinger)))
|
|
{
|
|
strLog.Format(_T("[%s][%d]set socketopt(SO_LINGER) failed. error_no = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
|
|
//设置套接字缓冲区
|
|
if ((SOCKET_ERROR == setsockopt(m_sockClient, SOL_SOCKET, SO_RCVBUF, (const char*)&m_iRcvBuf, sizeof(int))) ||
|
|
(SOCKET_ERROR == setsockopt(m_sockClient, SOL_SOCKET, SO_SNDBUF, (const char*)&m_iSndBuf, sizeof(int))) )
|
|
{
|
|
strLog.Format(_T("[%s][%d]set socketopt(SOCKET_BUF) failed. error_no = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
|
|
|
|
BOOL bKeepAlive = TRUE;
|
|
if (SOCKET_ERROR == setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (const char*)&bKeepAlive, sizeof(BOOL)))
|
|
{
|
|
strLog.Empty();
|
|
strLog.Format(_T("[%s][%d]Set keep alive failed.error = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
bool CTcpClient::ConnectServer(CString strAddr, WORD wPort)
|
|
{
|
|
CString strLog;
|
|
if (INVALID_SOCKET == m_sockClient)
|
|
{
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
AfxMessageBox(_T("请初始化套接字"));
|
|
else
|
|
MessageBoxEx(NULL, _T("Please initial socket."), STRING_MESSAGEBOXEX_TITLE, MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
strLog.Format(_T("[%s][%d] INVALID_SOCKET == m_sockClient"), MODULE_NAME, __LINE__);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
struct sockaddr_in socket_DstAddr;
|
|
socket_DstAddr.sin_family = AF_INET;
|
|
socket_DstAddr.sin_port = htons(wPort);
|
|
socket_DstAddr.sin_addr.S_un.S_addr = inet_addr(strAddr.GetBuffer(0));
|
|
if (SOCKET_ERROR == connect(m_sockClient, (struct sockaddr*)&socket_DstAddr, sizeof(sockaddr)))
|
|
{
|
|
strLog.Format(_T("[%s][%d]connect to %s:%d error = %d failed. m_sockClient=%d"), MODULE_NAME, __LINE__, strAddr, wPort, WSAGetLastError(), m_sockClient);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
|
|
strLog.Format(_T("[%s][%d]connect to %s:%d success. m_sockClient=%d"), MODULE_NAME, __LINE__, strAddr, wPort, m_sockClient);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
InitialClient();
|
|
m_bIsConnect = true;
|
|
return true;
|
|
}
|
|
|
|
bool CTcpClient::ConnectToServer(CString strIP, WORD wPort)
|
|
{
|
|
CString strLog;
|
|
if (ConnectServer(strIP,wPort))
|
|
{
|
|
m_strIP = strIP;
|
|
m_wPort = wPort;
|
|
strLog.Format(_T("zm:CTcpClient::ConnectToServer success m_strIP=%s , Port=%d"), strIP, wPort);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return true;
|
|
}
|
|
strLog.Format(_T("zm:CTcpClient::ConnectToServer failed m_strIP=%s , Port=%d"), strIP, wPort);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
|
|
|
|
int CTcpClient::SendData(const char*pData, int wLen)
|
|
{
|
|
CString strErr = _T("");
|
|
if (!GetConnectStatus())
|
|
{
|
|
strErr.Format(_T("[%s][%d]link has been interrupt before send data error"), MODULE_NAME, __LINE__);
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
return -1;
|
|
}
|
|
int iLen = send(m_sockClient, pData, wLen, 0);
|
|
if (SOCKET_ERROR == iLen)
|
|
{
|
|
strErr.Format(_T("[%s][%d]send data error, error = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
return 0;
|
|
}
|
|
|
|
CString strLog,strContent;
|
|
strLog.Format(_T("[%s][%d]CTcpClient::SendData size=%d\n send data:"), MODULE_NAME, __LINE__, iLen);
|
|
//打印接收数据流
|
|
unsigned char *pszTempData = (unsigned char*)pData;
|
|
for (int i = 0; i < iLen; i++)
|
|
{
|
|
strContent.AppendFormat("%02x ", pszTempData[i]);
|
|
}
|
|
strLog.AppendFormat(_T("%s\n"), strContent);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return iLen;
|
|
}
|
|
|
|
bool CTcpClient::CloseConnect()
|
|
{
|
|
CString strLog;
|
|
strLog.Format(_T("[%s][%d]zm: closesocket m_sockClient=%d"), MODULE_NAME, __LINE__, m_sockClient);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
if (INVALID_SOCKET == m_sockClient)
|
|
{
|
|
return true;
|
|
}
|
|
if (SOCKET_ERROR == closesocket(m_sockClient))
|
|
{
|
|
strLog.Format(_T("[%s][%d]zm: closesocket error, errorno = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
m_sockClient = INVALID_SOCKET;
|
|
return false;
|
|
}
|
|
m_bIsConnect = false;
|
|
strLog.Format(_T("[%s][%d]zm: closesocket success end"), MODULE_NAME, __LINE__);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
m_sockClient = INVALID_SOCKET;
|
|
return true;
|
|
}
|
|
bool CTcpClient::GetConnectStatus()
|
|
{
|
|
CString strLog;
|
|
if (!m_bIsConnect || (INVALID_SOCKET == m_sockClient))
|
|
{
|
|
strLog.Format(_T("[%s][%d]zm:CTcpClient::GetConnectStatus:m_bIsConnect=%d,m_sockClient=%d"), MODULE_NAME, __LINE__, m_bIsConnect, m_sockClient);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
}
|
|
FD_SET fdReadSet;
|
|
FD_ZERO(&fdReadSet);
|
|
FD_SET(m_sockClient, &fdReadSet);
|
|
struct timeval stTimeVal;
|
|
stTimeVal.tv_sec = 0;
|
|
stTimeVal.tv_usec = 0;
|
|
int iRet = select(m_sockClient+1, &fdReadSet, NULL, NULL, &stTimeVal);
|
|
CString strErr;
|
|
char msg[1] = {0};
|
|
if (SOCKET_ERROR == iRet)
|
|
{
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d] zm:CTcpClient::GetConnectStatus() select error in CheckLinkStatus, errorno = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
m_bIsConnect = false;
|
|
}
|
|
if (iRet > 0)
|
|
{
|
|
int iRecvLen = recv(m_sockClient, msg, sizeof(msg), MSG_PEEK);
|
|
if (iRecvLen <= 0)
|
|
{
|
|
//如果此时<=0,则表示收到了FIN包或者连接出了问题
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d]zm:CTcpClient::GetConnectStatus() LinkStatus has been interrupt"), MODULE_NAME, __LINE__);
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
m_bIsConnect = false;
|
|
}
|
|
CString strLog,strContent;
|
|
//打印接收数据流
|
|
unsigned char *pszTempData = (unsigned char*)msg;
|
|
for (int i = 0; i < iRecvLen; i++)
|
|
{
|
|
strContent.AppendFormat(" %02x", pszTempData[i]);
|
|
}
|
|
strLog.Format(_T("[%s][%d]CTcpClient::GetConnectStatus() recv data size=%d\n recv data:%s\n"), MODULE_NAME, __LINE__, iRecvLen, strContent);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
strContent.Empty();
|
|
}
|
|
|
|
return m_bIsConnect;
|
|
}
|
|
|
|
bool CTcpClient::ReConnect()
|
|
{
|
|
// Disconnect();
|
|
//在这里必须释放上一个socket资源,并重新申请新的socket才能重新连接上
|
|
//如果只是关闭连接,再重新连接,则无法成功,不知道为啥
|
|
CString strLog;
|
|
strLog.Format(_T("zm:CTcpClient::ReConnect() begin"));
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
CloseConnect();
|
|
if (InitailTcp())
|
|
{
|
|
strLog.Format(_T("zm:CTcpClient::ReConnect() "));
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return ConnectToServer(m_strIP, m_wPort);
|
|
}
|
|
else
|
|
{
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
AfxMessageBox(_T("套接字初始化失败"));
|
|
else
|
|
MessageBoxEx(NULL, _T("Socket initialization failed."), STRING_MESSAGEBOXEX_TITLE, MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
}
|
|
|
|
strLog.Format(_T("zm:CTcpClient::ReConnect() end"));
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
bool CTcpClient::RecvData(char*pData, int iLen,int &iActualLen)
|
|
{
|
|
CString strErr = _T("");
|
|
// if (!GetConnectStatus())
|
|
// {
|
|
// strErr.Format(_T("[%s][%d]link has been interrupt before recv data error"), MODULE_NAME, __LINE__);
|
|
// CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
// return false;
|
|
// }
|
|
if (!m_bIsConnect)
|
|
{
|
|
strErr.Format(_T("[%s][%d]zm:CTcpClient::RecvData() link has been interrupt before recv data error=%d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
return false;
|
|
}
|
|
FD_SET fdReadSet;
|
|
FD_ZERO(&fdReadSet);
|
|
FD_SET(m_sockClient, &fdReadSet);
|
|
struct timeval stTimeVal;
|
|
stTimeVal.tv_sec = 0;
|
|
stTimeVal.tv_usec = 25000;
|
|
int iRet = select(m_sockClient+1, &fdReadSet, NULL, NULL, &stTimeVal);
|
|
if (SOCKET_ERROR == iRet)
|
|
{
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d]select error in RecvData, errorno = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
return false;
|
|
}
|
|
else if (0 == iRet)
|
|
{
|
|
iActualLen = 0;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (FD_ISSET(m_sockClient, &fdReadSet)>0)
|
|
{
|
|
int iRecvLen = recv(m_sockClient, pData, iLen, 0);
|
|
if (iRecvLen <= 0)
|
|
{
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d]link interrupt in RecvData, errorno = %d"), MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
m_bIsConnect = false;
|
|
return false;
|
|
}
|
|
iActualLen = iRecvLen;
|
|
|
|
CString strLog,strContent;
|
|
strLog.Format(_T("[%s][%d]CTcpClient::RecvData recv size=%d\n recv data:"), MODULE_NAME, __LINE__, iRecvLen);
|
|
//CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
//打印接收数据流
|
|
unsigned char *pszTempData = (unsigned char*)pData;
|
|
for (int i = 0; i < iRecvLen; i++)
|
|
{
|
|
strContent.AppendFormat("%02x ", pszTempData[i]);
|
|
}
|
|
strLog.AppendFormat(_T("%s\n"),strContent);
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d]FD_ISSET is not detect read signal when select found read signal,errorno = %d"),MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool CTcpClient::Disconnect()
|
|
{
|
|
if (m_sockClient == INVALID_SOCKET )
|
|
{
|
|
return true;
|
|
}
|
|
m_bIsConnect = false;
|
|
CString strLog;
|
|
strLog.Format(_T("zm:CTcpClient::Disconnect() m_bIsConnect = false"));
|
|
CFileOperTools::GetInstance()->WriteComLog(strLog);
|
|
shutdown(m_sockClient, SHUT_RDWR);
|
|
return true;
|
|
|
|
}
|
|
|
|
bool CTcpClient::ClearRecvBuffer()
|
|
{
|
|
if (INVALID_SOCKET == m_sockClient)
|
|
{
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
AfxMessageBox(_T("套接字在ClearRecvBuffer中无效"));
|
|
else
|
|
MessageBoxEx(NULL, _T("The socket is invalid in ClearRecvBuffer."), STRING_MESSAGEBOXEX_TITLE, MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
return false;
|
|
}
|
|
//如果处于断练状态,则不需要进行操作
|
|
if (!m_bIsConnect)
|
|
{
|
|
return true;
|
|
}
|
|
if (NULL == m_pClearRcvBuf)
|
|
{
|
|
m_pClearRcvBuf = new char[m_iRcvBuf];
|
|
}
|
|
CString strErr = _T("");
|
|
struct timeval stTimeVal;
|
|
stTimeVal.tv_sec = 0;
|
|
stTimeVal.tv_usec = 1000;
|
|
bool bRes = true;
|
|
fd_set fdsRead;
|
|
|
|
FD_ZERO(&fdsRead);
|
|
FD_SET(m_sockClient, &fdsRead);
|
|
int iRet = select(m_sockClient+1, &fdsRead, NULL, NULL, &stTimeVal);
|
|
int iRecvLen = 0;
|
|
if (iRet > 0)
|
|
{
|
|
if (FD_ISSET(m_sockClient, &fdsRead) > 0)
|
|
{
|
|
iRecvLen = recv(m_sockClient, m_pClearRcvBuf, m_iRcvBuf, 0);
|
|
}
|
|
else
|
|
{
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d]FD_ISSET is not detect read signal when select found read signal,errorno = %d"),MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
bRes = false;
|
|
}
|
|
}
|
|
else if (iRet < 0)
|
|
{
|
|
strErr.Empty();
|
|
strErr.Format(_T("[%s][%d]select error in ClearRecvBuffer,errorno = %d"),MODULE_NAME, __LINE__, WSAGetLastError());
|
|
CFileOperTools::GetInstance()->WriteComLog(strErr);
|
|
bRes = false;
|
|
}
|
|
|
|
/*if (iRecvLen > 0)
|
|
{
|
|
CString strContent;
|
|
CString strPrintContent;
|
|
strContent.Format(_T("[%s][%d]CTcpClient::GetConnectStatus() recv data begin size=%d------\n"), MODULE_NAME, __LINE__, iRecvLen);
|
|
//CFileOperTools::GetInstance()->WriteComLog(strContent);
|
|
//打印接收数据流
|
|
unsigned char *pszTempData = (unsigned char*)m_pClearRcvBuf;
|
|
for (int i = 0; i < iRecvLen; i++)
|
|
{
|
|
strContent.AppendFormat(" %02x", pszTempData[i]);
|
|
strPrintContent.AppendFormat("%c", pszTempData[i]);
|
|
if ((i != 0 && i % 15 == 0) || (i == iRecvLen - 1))
|
|
{
|
|
strContent += "|";
|
|
strContent += strPrintContent;
|
|
//strContent += "\n";
|
|
CFileOperTools::GetInstance()->WriteComLog(strContent);
|
|
strContent.Empty();
|
|
strPrintContent.Empty();
|
|
}
|
|
}
|
|
strContent.Format(_T("[%s][%d]CTcpClient::GetConnectStatus() recv data end size=%d--------\n"), MODULE_NAME, __LINE__, iRecvLen);
|
|
CFileOperTools::GetInstance()->WriteComLog(strContent);
|
|
} */
|
|
return bRes;
|
|
} |