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