NetComm-TCPConnect

#pragma once


#include <winsock2.h>
#include <string>
#include "CommonDefine.h"
#include "CommuAnalyzer.h"
#include "CommuApplication.h"
#include "CCriticalSectionGuard.h"


class CTCPConnect
{
public:
  CTCPConnect(void);
  virtual ~CTCPConnect(void);
  
public:
  
  /*
  * Desc: 
  *     启动网络通讯
  * Pram:
  *     strIP             决定服务端侦听IP还是客户端需要连接的服务端IP
  *     siPort            决定服务端侦听端口还是客户端需要连接的服务端Port
  *     enMode            决定阻塞还是非阻塞模型
  *     bReconnect        决定是否可底层重连,默认不重连  【客户端模型下适用】
  *     iConnectTimeout   连接超时(以秒为单位,默认10秒)  【客户端模型下适用】
  * Retr:
  *     oid              成功:true;  失败:false
  */
  virtual bool Start(std::string& strIP, unsigned short& siPort, TCPCONNECT::BLOCKING_MODE& enMode, bool bReconnect = false, int iConnectTimeout = 10) = 0;


  /*
  * Desc: 
  *     停止网络通讯
  * Pram:
  *     bEnforce     决定是否强制停止   
  * Retr:
  *     void         成功:true;  失败:false
  */
  virtual bool Stop(bool bEnforce = false) = 0;
 
  /*
  * Desc: 
  *     往某个连接发送数据
  * Pram:
  *     refConnectInfo    通讯连接信息
  *     pszSendBuf        发送数据
  *     iSendBufLen       发送数据长度
  * Retr:
  *     void              成功:true;  失败:false
  */
  virtual bool SendData(TCPCONNECT::CONNECT_INFO& refConnectInfo, char* pszSendBuf, int iSendBufLen) = 0;


  /*
  * Desc: 
  *     设置本地的网络接收缓冲区大小
  * Pram:
  *     iBufferSize  大小   
  * Retr:
  *     void         无返回
  */
  void SetRecvBufferSize(int iBufferSize) { m_iMaxNetRecvBufferSize = iBufferSize; };
  
  /*
  * Desc: 
  *     获取本地的网络接收缓冲区大小
  * Pram:
  *        
  * Retr:
  *     int          返回本地的网络接收缓冲区大小
  */
  int  GetRecvBufferSize() { return m_iMaxNetRecvBufferSize; };


  /*
  * Desc: 
  *     注册通讯分析器
  *     默认的通讯分析器只含简单的网络层组包解包逻辑逻辑,不包含对于业务协议的包。网络包规则如下:
  *         网络包头包括:包头识别码(回车换行符:0x0d0x0a)+ 一个字节的长度,无包尾
  *     注:当符合以下条件的情况下可以不调用该接口
  *       1、业务报文件长度小于 TCPConnect中定义的:最大网络接收缓冲区大小
  *       2、对网络包组包规则无特殊要求
  * Pram:
  *     pclCommuAnalyzer  该分析器必须实现网络包的组包与解包   
  * Retr:
  *     void              无返回
  */
  void RigisterPacker(CCommuAnalyzer* pclCommuAnalyzer);


  /*
  * Desc: 
  *     注册应用对象
  * Pram:
  *     pclCommuAnalyzer     必须实现接收、已经发送通知接口
  *         
  * Retr:
  *     void          无返回
  */
  void RigisterApp(CCommuApplication* pclCommuApplication);


  /*
  * Desc: 
  *     初始化网络环境
  * Pram:
  *        
  * Retr:
  *     void             无返回
  */
  static bool InitNetEnvironment();


protected:




  /*
  * Desc: 
  *     销毁网络环境
  * Pram:
  *        
  * Retr:
  *     void             无返回
  */
  bool DestroyNetEnvironment();


protected:
  CCommuAnalyzer*    m_pclCommuAnalyzer;
  CCommuApplication* m_pclCommuApplication;


private:
  int m_iMaxNetRecvBufferSize;    // 最大网络接收缓冲区大小

};


#include "stdafx.h"
#include "TCPConnect.h"


#include <iostream>
#include <assert.h>


#pragma comment(lib, "ws2_32.lib")




CTCPConnect::CTCPConnect(void)
:m_pclCommuAnalyzer(NULL)
,m_pclCommuApplication(NULL)
,m_iMaxNetRecvBufferSize(1024*4)
{
}




CTCPConnect::~CTCPConnect(void)
{
}


bool CTCPConnect::InitNetEnvironment()
{
bool bReturn = false;


WSADATA wsaData;
int iErr = 0;


iErr = WSAStartup(MAKEWORD(2, 2), &wsaData);//初始化Winsock服务
if (iErr != 0) 
{
//std::cout << "WSAStartup调用失败:" << iErr << std::endl;
}
else 
{
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
//std::cout << "未能发现可用的Winsock.dll版本" << std::endl;
WSACleanup();
}
else
{
bReturn = true;
}
}


return bReturn;
}


bool CTCPConnect::DestroyNetEnvironment()
{
bool bReturn = false;
WSACleanup();
return bReturn;
}


void CTCPConnect::RigisterPacker(CCommuAnalyzer* pclCommuAnalyzer)
{
assert(pclCommuAnalyzer != NULL);
m_pclCommuAnalyzer = pclCommuAnalyzer;
}


void CTCPConnect::RigisterApp(CCommuApplication* pclCommuApplication)
{
assert(pclCommuApplication != NULL);
m_pclCommuApplication = pclCommuApplication;
}


#pragma once
#include "tcpconnect.h"


class CTCPClient :
  public CTCPConnect
{
public:
  CTCPClient(void);
  ~CTCPClient(void);


  friend unsigned __stdcall StartRecv(void* pArguments);


public:


  bool Start(std::string& strIP, unsigned short& siPort, TCPCONNECT::BLOCKING_MODE& enMode, bool bReconnect = false, int iConnectTimeout = 10);


  bool Stop(bool bEnforce = false);


  bool SendData(TCPCONNECT::CONNECT_INFO& refConnectInfo, char* pszSendBuf, int iSendBufLen);


private:
  /*
  * Desc: 
  *     创建客户端环境
  * Pram:
  *     enMode      决定通讯的阻塞模式
  *         
  * Retr:
  *     SOCKET      通讯SOCKET句柄
  */
  SOCKET CreateClientEnvironment(TCPCONNECT::BLOCKING_MODE& enMode);


  /*
  * Desc: 
  *     连接服务器处理连接
  * Pram:
  *     sClient           通讯SOCKET句柄
  *     pszServerIP       服务端IP
  *     siServerPort      服务端PORT
  *     iConnectTimeout   连接超时(秒为单位)
  * Retr:
  *     bool              成功返回true,失败返回false
  */
  bool ConnectServer(SOCKET& sClient, char* pszServerIP, unsigned short& siServerPort, int iConnectTimeout);
  
  /*
  * Desc: 
  *     重连接服务器处理连接
  * Pram:
  *     sClient           通讯SOCKET句柄
  *     strServerIP       服务端IP
  *     siServerPort      服务端PORT
  *     iConnectTimeout   连接超时(秒为单位)
  * Retr:
  *     bool              成功返回true,失败返回false
  */
  bool ReConnectServer(SOCKET& sClient, std::string& strServerIP, short& siServerPort, int iConnectTimeout);


  /*
  * Desc: 
  *     连接服务器处理连接
  * Pram:
  *     sClientSocket 通讯SOCKET句柄
//   *     strServerIP   服务端IP
//   *     siServerPort  服务端PORT
  * Retr:
  *     bool          成功返回接收线程句柄,失败返回:INVALID_HANDLE_VALUE
  */
  HANDLE DealWithConnected(SOCKET& sClientSocket/*, std::string& strServerIP, short& siServerPort*/);
  
  /*
  * Desc: 
  *     以阻塞方式接收数据
  * Pram:
  *     stConnectDetailInfo   客户端详细信息,见CLIENT_DETAIL_INFO定义
  * Retr:
  *     bool                  处理成功:true;处理失败:false
  */
  bool DealBlockingRecv(TCPCONNECT::CLIENT_DETAIL_INFO& stConnectDetailInfo);
   
  /*
  * Desc: 
  *     以非阻塞方式接收数据
  * Pram:
  *     stConnectDetailInfo   客户端详细信息,见CLIENT_DETAIL_INFO定义
  * Retr:
  *     bool                  处理成功:true;处理失败:false
  */
  bool DealUnBlockingRecv(TCPCONNECT::CLIENT_DETAIL_INFO& stConnectDetailInfo);
     
  /*
  * Desc: 
  *     处理接收到数据缓冲区
  * Pram:
  *     stConnectDetailInfo   客户端详细信息,见CLIENT_DETAIL_INFO定义
  * Retr:
  *     bool                  处理成功:true;处理失败:false
  */
  void DealWithRecvBuffer(TCPCONNECT::CLIENT_DETAIL_INFO& stConnectDetailInfo);


  /*
  * Desc: 
  *     以阻塞方式发送数据
  * Pram:
  *     sClient         SOCKET 连接句柄
  *     pszNetPackage   网络报文
  *     iNetPackageLen  网络报文长度
  * Retr:
  *     bool            发送成功:true; 发送失败:false
  */
  bool SendDataByBlocking(SOCKET sClient, char* pszNetPackage, int iNetPackageLen);


  /*
  * Desc: 
  *     以非阻塞方式发送数据
  * Pram:
  *     sClient         SOCKET 连接句柄
  *     pszNetPackage   网络报文
  *     iNetPackageLen  网络报文长度
  * Retr:
  *     bool            发送成功:true; 发送失败:false
  */
  bool SendDataByUnBlocking(SOCKET sClient, char* pszNetPackage, int iNetPackageLen);
    


private:
  TCPCONNECT::CLIENT_DETAIL_INFO m_stConnectDetailInfo; // 连接信息
  bool          m_bReConnect;                 // 重连标识
  int           m_iConnectTimeout;
  TCPCONNECT::BLOCKING_MODE m_enBlockingMode; //阻塞模式
  HANDLE        m_hDealWithRecvThread; // 处理数据接收线程句柄
};


#include "StdAfx.h"
#include "TCPClient.h"
#include <iostream>
#include <process.h>




CTCPClient::CTCPClient(void)
:m_bReConnect(false)
,m_iConnectTimeout(10)
,m_hDealWithRecvThread(INVALID_HANDLE_VALUE)
{
memset(&m_stConnectDetailInfo, 0x00, sizeof(m_stConnectDetailInfo));
m_stConnectDetailInfo.stConnectInfo.iSocketHandle = INVALID_SOCKET;
m_stConnectDetailInfo.pclTcpConnect = this;
}




CTCPClient::~CTCPClient(void)
{
}
//启动客户端,初始化客户端环境并连接服务端
bool CTCPClient::Start(std::string& strIP, unsigned short& siPort, TCPCONNECT::BLOCKING_MODE& enMode, bool bReconnect, int iConnectTimeout)
{
bool bReturn = false;
m_bReConnect = bReconnect;
m_iConnectTimeout = iConnectTimeout;
m_enBlockingMode = enMode;


m_stConnectDetailInfo.stConnectInfo.iSocketHandle = INVALID_SOCKET;
strncpy_s(m_stConnectDetailInfo.stConnectInfo.szConnectIP, strIP.c_str(), min(sizeof(m_stConnectDetailInfo.stConnectInfo.szConnectIP), strIP.length()));
m_stConnectDetailInfo.stConnectInfo.siConnectPort = siPort;  


m_stConnectDetailInfo.stConnectInfo.iSocketHandle = CreateClientEnvironment(m_enBlockingMode);
if ( m_stConnectDetailInfo.stConnectInfo.iSocketHandle == INVALID_SOCKET ) 
{
std::cout << "创建客户端环境失败" << std::endl;
}
else 
{
SOCKET sClient = m_stConnectDetailInfo.stConnectInfo.iSocketHandle;
m_pclCommuApplication->NetEvent(*(TCPCONNECT::CONNECT_INFO*)&m_stConnectDetailInfo, (int)TCPCONNECT::CONNECTINT__EVENT);
bReturn = ConnectServer(sClient, m_stConnectDetailInfo.stConnectInfo.szConnectIP, m_stConnectDetailInfo.stConnectInfo.siConnectPort, m_iConnectTimeout);
if ( bReturn == false ) 
{
closesocket(m_stConnectDetailInfo.stConnectInfo.iSocketHandle);
m_stConnectDetailInfo.stConnectInfo.iSocketHandle = INVALID_SOCKET;
//DestroyNetEnvironment();
m_pclCommuApplication->NetEvent(*(TCPCONNECT::CONNECT_INFO*)&m_stConnectDetailInfo, (int)TCPCONNECT::CONNECT_FAILD_EVENT);
std::cout << "连接服务端失败,IP:" << m_stConnectDetailInfo.stConnectInfo.szConnectIP << " PORT:"<<m_stConnectDetailInfo.stConnectInfo.siConnectPort << std::endl;
}
else //连接服务端成功
{
sockaddr_in clientAddress;
int iddrLen = sizeof(clientAddress);
getsockname(sClient, (sockaddr*)&clientAddress, &iddrLen);
strncpy_s(m_stConnectDetailInfo.stConnectInfo.szLocalIp, inet_ntoa(clientAddress.sin_addr), min(sizeof(m_stConnectDetailInfo.stConnectInfo.szConnectIP), strlen(inet_ntoa(clientAddress.sin_addr))));
m_stConnectDetailInfo.stConnectInfo.siLocalPort = ntohs(clientAddress.sin_port);


bool bOptval = true;
setsockopt(m_stConnectDetailInfo.stConnectInfo.iSocketHandle, IPPROTO_TCP, TCP_NODELAY, (char*)&bOptval, sizeof(bOptval));
m_pclCommuApplication->NetEvent(*(TCPCONNECT::CONNECT_INFO*)&m_stConnectDetailInfo, (int)TCPCONNECT::CONNECT_SUCCESS_EVENT);//回调连接成功事件
SOCKADDR_IN localAddrIn;
int iLocalAddrInLen = sizeof(localAddrIn);
getsockname(m_stConnectDetailInfo.stConnectInfo.iSocketHandle, (sockaddr*)&localAddrIn, &iLocalAddrInLen);
std::cout << "连接服务端成功,IP:" << m_stConnectDetailInfo.stConnectInfo.szConnectIP << " PORT:"<<m_stConnectDetailInfo.stConnectInfo.siConnectPort << " 本地Port:" << ntohs(localAddrIn.sin_port) <<  std::endl;
m_hDealWithRecvThread = DealWithConnected(sClient/*, m_strServerIP, m_siServerPort*/);
if (m_hDealWithRecvThread == INVALID_HANDLE_VALUE)
{
closesocket(m_stConnectDetailInfo.stConnectInfo.iSocketHandle);
m_stConnectDetailInfo.stConnectInfo.iSocketHandle = INVALID_SOCKET;
//DestroyNetEnvironment();
std::cout << "创建处理连接线程失败" << std::endl;
}
else 
{
std::cout << "创建处理连接线程成功" << std::endl;
}
}
}




return bReturn;
}


bool CTCPClient::Stop(bool bEnforce)
{
bool bReturn = false;
if (m_hDealWithRecvThread != INVALID_HANDLE_VALUE)
{
m_bReConnect = false; // 禁止重连
closesocket(m_stConnectDetailInfo.stConnectInfo.iSocketHandle);
m_stConnectDetailInfo.stConnectInfo.iSocketHandle = INVALID_SOCKET;
if (bEnforce) 
{
TerminateThread(m_hDealWithRecvThread, 0);
}
else 
{
WaitForSingleObject(m_hDealWithRecvThread, INFINITE);
}
m_hDealWithRecvThread = INVALID_HANDLE_VALUE;


if (m_stConnectDetailInfo.pszRecvBuf != NULL) 
{
delete[] m_stConnectDetailInfo.pszRecvBuf;
}
//DestroyNetEnvironment();
bReturn = true;
}
else 
{
bReturn = true;
}
return bReturn;
}


bool CTCPClient::SendData(TCPCONNECT::CONNECT_INFO& refConnectInfo, char* pszSendBuf, int iSendBufLen)
{
bool bReturn = false;


//将输入的数据发送过去
//先组网络包增
char* pszNetPackage = NULL;
int   iNetPackageLen = 0;
if ( m_pclCommuAnalyzer->PackNetPackage( pszSendBuf, iSendBufLen, pszNetPackage, iNetPackageLen) == false) 
{
std::cout << "组包失败:( " << pszNetPackage << ")" << std::endl;
}
else 
{
if (m_enBlockingMode == TCPCONNECT::MODE_BLOCKING)//阻塞模式发送数据
{
bReturn = SendDataByBlocking(refConnectInfo.iSocketHandle, pszNetPackage, iNetPackageLen);
}
else //非阻塞模式发送数据
{
bReturn = SendDataByUnBlocking(refConnectInfo.iSocketHandle, pszNetPackage, iNetPackageLen);
}
if ( bReturn ) 
{
std::cout << "send 发送数据成功" << std::endl;
bReturn = true;
}
else 
{
std::cout << "send 发送数据失败" << std::endl;
}
}


if ( pszNetPackage )
{
delete[] pszNetPackage;
}


return bReturn;
}


// 创建客户端环境
SOCKET CTCPClient::CreateClientEnvironment(TCPCONNECT::BLOCKING_MODE& enMode)
{
SOCKET sClient = INVALID_SOCKET;
sClient = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( sClient == INVALID_SOCKET ) 
{
std::cout << "socket 创建失败:" << WSAGetLastError() << std::endl;
}
else 
{
DWORD dwMode = enMode;
if(ioctlsocket(sClient, FIONBIO, &dwMode) == SOCKET_ERROR) 
{
std::cout << "设置阻塞模型失败:" << WSAGetLastError() << std::endl;
closesocket(sClient);
sClient = INVALID_SOCKET;
}
else 
{
std::cout << "SOCKET模式设定:" << (enMode==0?"阻塞模式设定":"非阻塞模式设定") << std::endl;
}
}
return sClient;
}


//连接服务器处理连接,
bool CTCPClient::ConnectServer(SOCKET& sClient, char* pszServerIP, unsigned short& siServerPort, int iConnectTimeout)
{
bool bReturn = false;
SOCKADDR_IN   addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_addr.S_un.S_addr = inet_addr(pszServerIP);
addrServer.sin_port = htons(siServerPort);


fd_set fdWrite;
//timeval tv={1, 0};
timeval tv={3, 0};//select 超时时间设置为3秒,设置1秒时,未知原因连接server多次
int error = -1;
int len = sizeof(int);


//int iTimeoutCount = iConnectTimeout / 1;//连接超时次数
int iTimeoutCount = iConnectTimeout / 3 + 1;//连接超时次数
//add by wanyx 2016-12-30 阻止主从STG同时报盘
//connect采用非阻塞模式
if (m_enBlockingMode == TCPCONNECT::MODE_BLOCKING)//阻塞模式
{
DWORD dwMode = 1;
ioctlsocket(sClient, FIONBIO, &dwMode); // 设置为非阻塞模式连接服务端
}


while(true)
{
if(connect(sClient, (const sockaddr*)&addrServer, sizeof(addrServer)) != 0) //连接失败
{
FD_ZERO(&fdWrite);
FD_SET(sClient, &fdWrite);
int iRet = select(0, NULL, &fdWrite, NULL, &tv);
if(iRet == 0) 
{
if (iTimeoutCount-- == 0)

std::cout << "连接指定服务器超时,IP:" << inet_ntoa(addrServer.sin_addr) << " PORT:" << ntohs(addrServer.sin_port) << std::endl;
break;
}
else 
{
continue;
}
//        }
}
else if(iRet == -1) 
{
break;
}
else //socket可用
{
bReturn = true;        
break;
}
}
else 
{
bReturn = true;
break;
}
}


if (m_enBlockingMode == TCPCONNECT::MODE_BLOCKING)
{
DWORD dwMode = 0;
ioctlsocket(sClient, FIONBIO, &dwMode); // 重置阻塞模式
}
return bReturn;
}


HANDLE CTCPClient::DealWithConnected(SOCKET& sClientSocket/*, std::string& strServerIP, short& siServerPort*/)
{
HANDLE hThread = INVALID_HANDLE_VALUE;
unsigned uiThreadID;


m_stConnectDetailInfo.stConnectInfo.iSocketHandle = sClientSocket;
m_stConnectDetailInfo.iRecvBufferSize = GetRecvBufferSize();
m_stConnectDetailInfo.pszRecvBuf = new char[m_stConnectDetailInfo.iRecvBufferSize];
m_stConnectDetailInfo.strRecvBuf.clear(); // add by liusg 20170105 支持不确认长度的大数据接收
if (m_stConnectDetailInfo.pszRecvBuf == NULL) 
{
std::cout << "分配内存失败,所需大小:" << m_stConnectDetailInfo.iRecvBufferSize << std::endl;
}
else//创建接收线程
{
memset(m_stConnectDetailInfo.pszRecvBuf, 0x00, sizeof(m_stConnectDetailInfo.pszRecvBuf));
hThread = (HANDLE)_beginthreadex(NULL, 0, StartRecv, &m_stConnectDetailInfo, 0, &uiThreadID);
if (hThread == INVALID_HANDLE_VALUE) 
{
delete[] m_stConnectDetailInfo.pszRecvBuf;
}
}


return hThread;
}


unsigned __stdcall StartRecv(void* pArguments)
{
TCPCONNECT::CLIENT_DETAIL_INFO* pstConnectDetailInfo = (TCPCONNECT::CLIENT_DETAIL_INFO*)pArguments;


CTCPClient* pThis = (CTCPClient*)pstConnectDetailInfo->pclTcpConnect;
TCPCONNECT::CONNECT_INFO stConnectInfo;
memcpy(&stConnectInfo, pstConnectDetailInfo, sizeof(stConnectInfo));


bool bReconect = false;


__DoRecv:
memset(pstConnectDetailInfo->pszRecvBuf, 0x00, pstConnectDetailInfo->iRecvBufferSize);
bool bDealSuccess = false;
if (pThis->m_enBlockingMode == TCPCONNECT::MODE_BLOCKING) 
{
bDealSuccess = pThis->DealBlockingRecv(*pstConnectDetailInfo);
}
else 
{
bDealSuccess = pThis->DealUnBlockingRecv(*pstConnectDetailInfo);
}


if (bDealSuccess == false)
{
while(pThis->m_bReConnect == true) //重连
{
std::cout << "重连指定服务器" << std::endl;
closesocket(pstConnectDetailInfo->stConnectInfo.iSocketHandle);
pstConnectDetailInfo->stConnectInfo.iSocketHandle = INVALID_SOCKET;
pstConnectDetailInfo->stConnectInfo.iSocketHandle = pThis->CreateClientEnvironment(pThis->m_enBlockingMode);
SOCKET sClient = pstConnectDetailInfo->stConnectInfo.iSocketHandle;


pThis->m_pclCommuApplication->NetEvent(*(TCPCONNECT::CONNECT_INFO*)pstConnectDetailInfo, (int)TCPCONNECT::CONNECTINT__EVENT);
if(pThis->ConnectServer(sClient, pstConnectDetailInfo->stConnectInfo.szConnectIP, pstConnectDetailInfo->stConnectInfo.siConnectPort, pThis->m_iConnectTimeout))
{
pThis->m_pclCommuApplication->NetEvent(*(TCPCONNECT::CONNECT_INFO*)pstConnectDetailInfo, (int)TCPCONNECT::CONNECT_SUCCESS_EVENT);
SOCKADDR_IN localAddrIn;
int iLocalAddrInLen = sizeof(localAddrIn);
getsockname(pstConnectDetailInfo->stConnectInfo.iSocketHandle, (sockaddr*)&localAddrIn, &iLocalAddrInLen);
pstConnectDetailInfo->stConnectInfo.siLocalPort = ntohs(localAddrIn.sin_port);
std::cout << "连接服务端成功,IP:" <<  pstConnectDetailInfo->stConnectInfo.szConnectIP << " PORT:"<< pstConnectDetailInfo->stConnectInfo.siConnectPort << " 本地Port:" << ntohs(localAddrIn.sin_port) <<  std::endl;
goto __DoRecv;
}
}
closesocket(pstConnectDetailInfo->stConnectInfo.iSocketHandle);
}




std::cout << "退出接收处理线程" << std::endl;
_endthreadex(0);
return 0;
}


bool CTCPClient::DealBlockingRecv(TCPCONNECT::CLIENT_DETAIL_INFO& stConnectDetailInfo)
{
bool bReturn = false;
int iRcvSum = 0;


while(true) //阻塞recv,直到recv错误
{
int iRecv = recv(stConnectDetailInfo.stConnectInfo.iSocketHandle, stConnectDetailInfo.pszRecvBuf + stConnectDetailInfo.iRcvSum, stConnectDetailInfo.iRecvBufferSize - stConnectDetailInfo.iRcvSum, 0);
if (iRecv < 0 
|| (iRecv == 0 && (stConnectDetailInfo.iRecvBufferSize- stConnectDetailInfo.iRcvSum != 0))) 
{
m_pclCommuApplication->NetEvent(stConnectDetailInfo.stConnectInfo, (int)TCPCONNECT::CONNECT_BREAKED_EVENT);
std::cout << "recv 接收数据失败, ERROR =  " << WSAGetLastError() << std::endl;
break;
}
else 
{
std::cout << "recv 接收数据:" <<  iRecv   <<  "个字节" << std::endl;
stConnectDetailInfo.iRcvSum += iRecv;
DealWithRecvBuffer(stConnectDetailInfo);
}
}


return bReturn;
}


bool CTCPClient::DealUnBlockingRecv(TCPCONNECT::CLIENT_DETAIL_INFO& stConnectDetailInfo)
{
bool bReturn = false;


int iRcvSum = 0;
fd_set fdRead;
timeval tv={0, 100};


while(true) 
{
FD_ZERO(&fdRead);
FD_SET(stConnectDetailInfo.stConnectInfo.iSocketHandle, &fdRead);
int iRes = select(0, &fdRead, NULL, NULL, &tv );


if(iRes == 0) 
{
std::cout << "SELECT 接收数据超时ms :" << tv.tv_sec*1000 + tv.tv_usec / 1000 << std::endl;
continue; //超时继续监听
}
else if( iRes < 0 )//此处select失败,处理为 CONNECT_BREAKED_EVENT是否正确?
{     
std::cout << "select 接收数据失败: " << WSAGetLastError() << std::endl;
m_pclCommuApplication->NetEvent(stConnectDetailInfo.stConnectInfo, (int)TCPCONNECT::CONNECT_BREAKED_EVENT);
break;
}
else//socket 可用
{
if(FD_ISSET(stConnectDetailInfo.stConnectInfo.iSocketHandle, &fdRead)) 
{
int iRecv = 0;
do 
{
iRecv = recv(stConnectDetailInfo.stConnectInfo.iSocketHandle, stConnectDetailInfo.pszRecvBuf + stConnectDetailInfo.iRcvSum, stConnectDetailInfo.iRecvBufferSize - stConnectDetailInfo.iRcvSum, 0);
if (iRecv == 0 && (stConnectDetailInfo.iRecvBufferSize- stConnectDetailInfo.iRcvSum != 0)) 
{
closesocket(stConnectDetailInfo.stConnectInfo.iSocketHandle);
break;
}
if (iRecv < 0) 
{
if (WSAGetLastError() != 10035) 
{
std::cout << "recv 接收数据失败, ERROR =  " << WSAGetLastError() << std::endl;
closesocket(stConnectDetailInfo.stConnectInfo.iSocketHandle);
}
}
else 
{
stConnectDetailInfo.iRcvSum += iRecv;
// 处理已经接收到的缓冲区数据
DealWithRecvBuffer(stConnectDetailInfo);
}
} while (iRecv > 0); 
}
}
}


return bReturn;
}


void CTCPClient::DealWithRecvBuffer(TCPCONNECT::CLIENT_DETAIL_INFO& stConnectDetailInfo)
{
int iNetPackageLen = 0;
char* pszPackage = NULL;
int iPackageLen = 0;
int iSkipLen = 0;
int iHeadLen = 0;
int iTailLen = 0;
int iIsHave  = 0;
// modified by liusg 20170105 支持不确认长度的大数据接收
m_stConnectDetailInfo.strRecvBuf.append(std::string(stConnectDetailInfo.pszRecvBuf, stConnectDetailInfo.iRcvSum));
memset(stConnectDetailInfo.pszRecvBuf, 0x00, stConnectDetailInfo.iRcvSum);
stConnectDetailInfo.iRcvSum = 0;
while(true)
{
pszPackage = NULL;  
iPackageLen = 0;
iSkipLen = 0;
iHeadLen = 0;
iTailLen = 0;
//iIsHave = m_pclCommuAnalyzer->IsExistDirtyData(stConnectDetailInfo.pszRecvBuf, stConnectDetailInfo.iRcvSum, iSkipLen);
iIsHave = m_pclCommuAnalyzer->IsExistDirtyData(const_cast<char*>(m_stConnectDetailInfo.strRecvBuf.c_str()), m_stConnectDetailInfo.strRecvBuf.size(), iSkipLen);
if (iSkipLen > 0) 
{
m_stConnectDetailInfo.strRecvBuf.erase(0, iSkipLen);
m_pclCommuApplication->NetEvent(stConnectDetailInfo.stConnectInfo, TCPCONNECT::EVENT_TYPE::HAS_DIRTY_DATA_CLEAR);
}
if (iIsHave == -2) 
{
closesocket(stConnectDetailInfo.stConnectInfo.iSocketHandle);
m_pclCommuApplication->NetEvent(stConnectDetailInfo.stConnectInfo, TCPCONNECT::EVENT_TYPE::HAS_DIRTY_DATA_BREAK);
break;
}


if (m_pclCommuAnalyzer->IsHasFullPackage(const_cast<char*>(m_stConnectDetailInfo.strRecvBuf.c_str()), m_stConnectDetailInfo.strRecvBuf.size())) 
{
if(m_pclCommuAnalyzer->UnpackNetPackage(const_cast<char*>(m_stConnectDetailInfo.strRecvBuf.c_str()), m_stConnectDetailInfo.strRecvBuf.size(), pszPackage, iPackageLen, iHeadLen, iTailLen) == true) 
{
m_pclCommuApplication->FromNet(stConnectDetailInfo.stConnectInfo, pszPackage, iPackageLen);
m_stConnectDetailInfo.strRecvBuf.erase(0, iPackageLen);
}
}
else 
{
break;
}
continue; 
}
}


bool CTCPClient::SendDataByBlocking(SOCKET sClient, char* pszNetPackage, int iNetPackageLen)
{
bool bReturn = false;
int iIndex = 0;
int iNeedSendLen = iNetPackageLen;
while(iNeedSendLen > 0) //循环多次发送,直到发送完成为止
{
int iSend = send(sClient, pszNetPackage + iIndex, iNeedSendLen, 0);
if(iSend < 0) 
{
std::cout << "send 发送数据失败, 客户端已经关闭 " << WSAGetLastError() << std::endl;
break;
}
iNeedSendLen  -= iSend;
iIndex += iSend; 
}
if (iNeedSendLen == 0) 
{
bReturn = true;
}


return bReturn;
}


bool CTCPClient::SendDataByUnBlocking(SOCKET sClient, char* pszNetPackage, int iNetPackageLen)
{
bool bReturn = false;
int iIndex = 0;
int iNeedSendLen = iNetPackageLen;


while(iNeedSendLen > 0) 
{
__ReSend:
int iSend = send(sClient, pszNetPackage + iIndex, iNeedSendLen, 0);
if(iSend < 0) 
{
std::cout << "send 发送数据失败,服务端已经关闭 " << WSAGetLastError() << "iSend = " << iSend << std::endl;
int iLastError = WSAGetLastError();
//10035 - WSAEWOULDBLOCK 资源暂时不可用。对非阻塞套接字来说,如果请求操作不能立即执行的话,通常会返回这个错误。比如说,在一个非阻塞套接字上调用connect,就会返回这个错误。因为连接请求不能立即执行。
if ( iLastError == 10035)
{
Sleep(100);
goto __ReSend;

else 
{
std::cout << "输出特殊错误码-------------------------:" << WSAGetLastError() <<std::endl;
break;
}
}


iNeedSendLen  -= iSend;
iIndex += iSend; 
}


if (iNeedSendLen == 0) 
{
bReturn = true;
}


return bReturn;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值