Files
coco df489d5640 a
2026-07-03 16:05:30 +08:00

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;
}