Files
SimpleRemoter/client/IOCPClient.cpp

431 lines
11 KiB
C++
Raw Normal View History

// IOCPClient.cpp: implementation of the IOCPClient class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "IOCPClient.h"
#include <IOSTREAM>
#if USING_ZLIB
#include "zlib.h"
#define Z_FAILED(p) (Z_OK != (p))
#define Z_SUCCESS(p) (!Z_FAILED(p))
#else
#if USING_LZ4
#include "lz4/lz4.h"
#pragma comment(lib, "lz4/lz4.lib")
#define Z_FAILED(p) (0 == (p))
#define Z_SUCCESS(p) (!Z_FAILED(p))
#define compress(dest, destLen, source, sourceLen) LZ4_compress_default((const char*)source, (char*)dest, sourceLen, *(destLen))
#define uncompress(dest, destLen, source, sourceLen) LZ4_decompress_safe((const char*)source, (char*)dest, sourceLen, *(destLen))
#else
#include "zstd/zstd.h"
#pragma comment(lib, "zstd/zstd.lib")
#define Z_FAILED(p) ZSTD_isError(p)
#define Z_SUCCESS(p) (!Z_FAILED(p))
#define compress(dest, destLen, source, sourceLen) ZSTD_compress(dest, *(destLen), source, sourceLen, ZSTD_CLEVEL_DEFAULT)
#define uncompress(dest, destLen, source, sourceLen) ZSTD_decompress(dest, *(destLen), source, sourceLen)
#endif
#endif
#include <assert.h>
#include "Manager.h"
using namespace std;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
VOID IOCPClient::setManagerCallBack(CManager* Manager)
{
m_Manager = Manager;
}
IOCPClient::IOCPClient(bool exit_while_disconnect)
{
m_Manager = NULL;
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
2019-01-10 19:35:03 +08:00
m_sClientSocket = INVALID_SOCKET;
m_hWorkThread = NULL;
m_bWorkThread = S_STOP;
memset(m_szPacketFlag, 0, sizeof(m_szPacketFlag));
memcpy(m_szPacketFlag,"Shine",FLAG_LENGTH);
m_bIsRunning = TRUE;
m_bConnected = FALSE;
InitializeCriticalSection(&m_cs);
m_exit_while_disconnect = exit_while_disconnect;
}
IOCPClient::~IOCPClient()
{
m_bIsRunning = FALSE;
if (m_sClientSocket!=INVALID_SOCKET)
{
closesocket(m_sClientSocket);
m_sClientSocket = INVALID_SOCKET;
}
if (m_hWorkThread!=NULL)
{
CloseHandle(m_hWorkThread);
m_hWorkThread = NULL;
}
WSACleanup();
while (S_RUN == m_bWorkThread)
Sleep(10);
DeleteCriticalSection(&m_cs);
m_bWorkThread = S_END;
}
2019-05-07 20:27:02 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡIP<49><50>ַ
inline string GetIPAddress(const char *hostName)
{
struct hostent *host = gethostbyname(hostName);
#ifdef _DEBUG
printf("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ: %s.\n", host->h_addrtype == AF_INET ? "IPV4" : "IPV6");
for (int i = 0; host->h_addr_list[i]; ++i)
printf("<EFBFBD><EFBFBD>ȡ<EFBFBD>ĵ<EFBFBD>%d<><64>IP: %s\n", i+1, inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
#endif
if (host == NULL || host->h_addr_list == NULL)
return "";
return host->h_addr_list[0] ? inet_ntoa(*(struct in_addr*)host->h_addr_list[0]) : "";
2019-05-07 20:27:02 +08:00
}
BOOL IOCPClient::ConnectServer(const char* szServerIP, unsigned short uPort)
{
m_sClientSocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2019-01-10 19:35:03 +08:00
if (m_sClientSocket == SOCKET_ERROR)
{
return FALSE;
}
//<2F><><EFBFBD><EFBFBD>sockaddr_in<69>ṹ Ҳ<><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ض˵Ľṹ
sockaddr_in ServerAddr;
ServerAddr.sin_family = AF_INET; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> IP
ServerAddr.sin_port = htons(uPort);
2019-05-07 20:27:02 +08:00
// <20><>szServerIP<49><50><EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IPת<50><D7AA>
string server = ('0' <= szServerIP[0] && szServerIP[0] <= '9')
? szServerIP : GetIPAddress(szServerIP);
ServerAddr.sin_addr.S_un.S_addr = inet_addr(server.c_str());
2019-01-10 19:35:03 +08:00
if (connect(m_sClientSocket,(SOCKADDR *)&ServerAddr,sizeof(sockaddr_in)) == SOCKET_ERROR)
{
if (m_sClientSocket!=INVALID_SOCKET)
{
closesocket(m_sClientSocket);
m_sClientSocket = INVALID_SOCKET;
}
return FALSE;
}
const int chOpt = 1; // True
// Set KeepAlive <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><CBB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (setsockopt(m_sClientSocket, SOL_SOCKET, SO_KEEPALIVE,
(char *)&chOpt, sizeof(chOpt)) == 0)
{
// <20><><EFBFBD>ó<EFBFBD>ʱ<EFBFBD><CAB1>ϸ<EFBFBD><CFB8>Ϣ
tcp_keepalive klive;
klive.onoff = 1; // <20><><EFBFBD>ñ<EFBFBD><C3B1><EFBFBD>
klive.keepalivetime = 1000 * 60 * 3; // 3<><33><EFBFBD>ӳ<EFBFBD>ʱ Keep Alive
klive.keepaliveinterval = 1000 * 5; // <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD>Ϊ5<CEAA><35> Resend if No-Reply
WSAIoctl(m_sClientSocket, SIO_KEEPALIVE_VALS,&klive,sizeof(tcp_keepalive),
NULL, 0,(unsigned long *)&chOpt,0,NULL);
}
if (m_hWorkThread == NULL){
m_hWorkThread = (HANDLE)CreateThread(NULL, 0,
2019-01-10 19:35:03 +08:00
(LPTHREAD_START_ROUTINE)WorkThreadProc,(LPVOID)this, 0, NULL);
m_bWorkThread = m_hWorkThread ? S_RUN : S_STOP;
}
std::cout<<"<EFBFBD><EFBFBD><EFBFBD>ӷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˳ɹ<EFBFBD>.\n";
m_bConnected = TRUE;
return TRUE;
}
DWORD WINAPI IOCPClient::WorkThreadProc(LPVOID lParam)
{
IOCPClient* This = (IOCPClient*)lParam;
char* szBuffer = new char[MAX_RECV_BUFFER];
fd_set fd;
const struct timeval tm = { 2, 0 };
while (This->IsRunning()) // û<><C3BB><EFBFBD>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD>һֱ<D2BB><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD>
{
if(!This->IsConnected())
{
Sleep(50);
continue;
}
FD_ZERO(&fd);
FD_SET(This->m_sClientSocket, &fd);
int iRet = select(NULL, &fd, NULL, NULL, &tm);
if (iRet <= 0)
{
if (iRet == 0) Sleep(50);
else
{
printf("[select] return %d, GetLastError= %d. \n", iRet, WSAGetLastError());
This->Disconnect(); //<2F><><EFBFBD>մ<EFBFBD><D5B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if(This->m_exit_while_disconnect)
break;
}
}
else if (iRet > 0)
{
memset(szBuffer, 0, MAX_RECV_BUFFER);
int iReceivedLength = recv(This->m_sClientSocket,
szBuffer, MAX_RECV_BUFFER, 0); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ض˷<D8B6><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (iReceivedLength <= 0)
{
int a = GetLastError();
This->Disconnect(); //<2F><><EFBFBD>մ<EFBFBD><D5B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if(This->m_exit_while_disconnect)
break;
}else{
//<2F><>ȷ<EFBFBD><C8B7><EFBFBD>վ͵<D5BE><CDB5><EFBFBD>OnRead<61><64><EFBFBD><EFBFBD><><D7AA>OnRead
2019-01-10 19:35:03 +08:00
This->OnServerReceiving(szBuffer, iReceivedLength);
if (This->m_Manager!=NULL && This->m_Manager->m_bIsDead)
{
printf("****** Recv bye bye ******\n");
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>˳<EFBFBD><CBB3>ͻ<EFBFBD><CDBB>˺<EFBFBD><CBBA><EFBFBD><EFBFBD>ضˣ<D8B6><CBA3><EFBFBD><EFBFBD>˳<EFBFBD><CBB3>ͻ<EFBFBD><CDBB><EFBFBD>
extern BOOL g_bExit;
g_bExit = This->m_Manager->m_bIsDead;
break;
}
}
}
}
This->m_bWorkThread = S_STOP;
This->m_bIsRunning = FALSE;
delete[] szBuffer;
return 0xDEAD;
}
VOID IOCPClient::OnServerReceiving(char* szBuffer, ULONG ulLength)
{
try
{
assert (ulLength > 0);
//<2F><><EFBFBD>½ӵ<C2BD><D3B5><EFBFBD><EFBFBD>ݽ<EFBFBD><DDBD>н<EFBFBD>ѹ<EFBFBD><D1B9>
m_CompressedBuffer.WriteBuffer((LPBYTE)szBuffer, ulLength);
2019-01-10 19:35:03 +08:00
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>С <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǾͲ<C7BE><CDB2><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
while (m_CompressedBuffer.GetBufferLength() > HDR_LENGTH)
{
char szPacketFlag[FLAG_LENGTH + 3] = {0};
LPBYTE src = m_CompressedBuffer.GetBuffer();
CopyMemory(szPacketFlag, src, FLAG_LENGTH);
//<2F>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>ͷ
if (memcmp(m_szPacketFlag, szPacketFlag, FLAG_LENGTH) != 0)
{
throw "Bad Buffer";
}
2019-01-10 19:35:03 +08:00
ULONG ulPackTotalLength = 0;
CopyMemory(&ulPackTotalLength, m_CompressedBuffer.GetBuffer(FLAG_LENGTH),
sizeof(ULONG));
2019-01-10 19:35:03 +08:00
//--- <20><><EFBFBD>ݵĴ<DDB5>С<EFBFBD><D0A1>ȷ<EFBFBD>ж<EFBFBD>
ULONG len = m_CompressedBuffer.GetBufferLength();
if (ulPackTotalLength && len >= ulPackTotalLength)
{
m_CompressedBuffer.ReadBuffer((PBYTE)szPacketFlag, FLAG_LENGTH);//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7> shine
2019-01-10 19:35:03 +08:00
m_CompressedBuffer.ReadBuffer((PBYTE) &ulPackTotalLength, sizeof(ULONG));
ULONG ulOriginalLength = 0;
m_CompressedBuffer.ReadBuffer((PBYTE) &ulOriginalLength, sizeof(ULONG));
//50
2019-01-10 19:35:03 +08:00
ULONG ulCompressedLength = ulPackTotalLength - HDR_LENGTH;
PBYTE CompressedBuffer = new BYTE[ulCompressedLength];
PBYTE DeCompressedBuffer = new BYTE[ulOriginalLength];
m_CompressedBuffer.ReadBuffer(CompressedBuffer, ulCompressedLength);
2019-01-10 19:35:03 +08:00
int iRet = uncompress(DeCompressedBuffer,
&ulOriginalLength, CompressedBuffer, ulCompressedLength);
2019-01-10 19:35:03 +08:00
if (Z_SUCCESS(iRet))//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD>ɹ<EFBFBD>
{
2019-01-10 19:35:03 +08:00
CBuffer m_DeCompressedBuffer;
m_DeCompressedBuffer.WriteBuffer(DeCompressedBuffer,
ulOriginalLength);
2019-01-10 19:35:03 +08:00
//<2F><>ѹ<EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD>ݺͳ<DDBA><CDB3>ȴ<EFBFBD><C8B4>ݸ<EFBFBD><DDB8><EFBFBD><EFBFBD><EFBFBD>Manager<65><72><EFBFBD>д<EFBFBD><D0B4><EFBFBD> ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD>̬
//<2F><><EFBFBD><EFBFBD>m_pManager<65>е<EFBFBD><D0B5><EFBFBD><EFBFBD>һ<E0B2BB><D2BB><EFBFBD><EFBFBD><EFBFBD>ɵ<EFBFBD><C9B5>õ<EFBFBD>OnReceive<76><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
m_Manager->OnReceive((PBYTE)m_DeCompressedBuffer.GetBuffer(0),
m_DeCompressedBuffer.GetBufferLength());
}
else{
printf("[ERROR] uncompress fail: dstLen %d, srcLen %d\n", ulOriginalLength, ulCompressedLength);
delete [] CompressedBuffer;
delete [] DeCompressedBuffer;
throw "Bad Buffer";
}
2019-01-10 19:35:03 +08:00
delete [] CompressedBuffer;
delete [] DeCompressedBuffer;
#if _DEBUG
printf("[INFO] uncompress succeed data len: %d expect: %d\n", len, ulPackTotalLength);
#endif
}
else {
printf("[WARNING] OnServerReceiving incomplete data: %d expect: %d\n", len, ulPackTotalLength);
break;
}
}
}catch(...) {
m_CompressedBuffer.ClearBuffer();
printf("[ERROR] OnServerReceiving catch an error \n");
}
}
2019-09-07 10:47:50 +08:00
// <20><>server<65><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȽϺ<C8BD>ʱ<EFBFBD><CAB1>
// <20>ر<EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>SendWithSplit<69>ȽϺ<C8BD>ʱ<EFBFBD><CAB1>
2019-01-18 17:37:15 +08:00
BOOL IOCPClient::OnServerSending(const char* szBuffer, ULONG ulOriginalLength) //Hello
{
2019-05-11 11:28:58 +08:00
AUTO_TICK(50);
2019-01-10 19:35:03 +08:00
assert (ulOriginalLength > 0);
{
2019-01-10 19:35:03 +08:00
//<2F><><EFBFBD><EFBFBD>1.001<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD>õ<EFBFBD><EFBFBD>ڴ<EFBFBD><EFBFBD>ռ<EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> +12
//<2F><>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>// HelloWorld 10 22
//<2F><><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9> ѹ<><D1B9><EFBFBD>㷨 ΢<><CEA2><EFBFBD>
//nSize = 436
2019-01-10 19:35:03 +08:00
//destLen = 448
2019-09-07 10:47:50 +08:00
#if USING_COMPRESS
#if USING_ZLIB
2019-01-10 19:35:03 +08:00
unsigned long ulCompressedLength = (double)ulOriginalLength * 1.001 + 12;
#elif USING_LZ4
unsigned long ulCompressedLength = LZ4_compressBound(ulOriginalLength);
#else
unsigned long ulCompressedLength = ZSTD_compressBound(ulOriginalLength);
#endif
2019-01-10 19:35:03 +08:00
LPBYTE CompressedBuffer = new BYTE[ulCompressedLength];
2019-01-10 19:35:03 +08:00
int iRet = compress(CompressedBuffer, &ulCompressedLength, (PBYTE)szBuffer, ulOriginalLength);
if (Z_FAILED(iRet))
{
printf("[ERROR] compress failed \n");
delete [] CompressedBuffer;
return FALSE;
}
#if !USING_ZLIB
ulCompressedLength = iRet;
#endif
2019-09-07 10:47:50 +08:00
#else // <20><>ѹ<EFBFBD><D1B9>
unsigned long ulCompressedLength = ulOriginalLength;
LPBYTE CompressedBuffer = (LPBYTE)szBuffer;
#endif
2019-01-10 19:35:03 +08:00
ULONG ulPackTotalLength = ulCompressedLength + HDR_LENGTH;
CBuffer m_WriteBuffer;
m_WriteBuffer.WriteBuffer((PBYTE)m_szPacketFlag, FLAG_LENGTH);
2019-01-10 19:35:03 +08:00
m_WriteBuffer.WriteBuffer((PBYTE) &ulPackTotalLength,sizeof(ULONG));
// 5 4
//[Shine][ 30 ]
m_WriteBuffer.WriteBuffer((PBYTE)&ulOriginalLength, sizeof(ULONG));
// 5 4 4
2019-01-10 19:35:03 +08:00
//[Shine][ 30 ][5]
m_WriteBuffer.WriteBuffer(CompressedBuffer,ulCompressedLength);
2019-09-07 10:47:50 +08:00
#if USING_COMPRESS // ʹ<><CAB9>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><E3B7A8><EFBFBD><EFBFBD>Ҫ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>
delete [] CompressedBuffer;
2019-01-10 19:35:03 +08:00
CompressedBuffer = NULL;
2019-09-07 10:47:50 +08:00
#endif
2019-01-10 19:35:03 +08:00
// <20>ֿ鷢<D6BF><E9B7A2>
//shine[0035][0010][HelloWorld+12]
return SendWithSplit((char*)m_WriteBuffer.GetBuffer(), m_WriteBuffer.GetBufferLength(),
MAX_SEND_BUFFER);
}
}
// 5 2 // 2 2 1
2019-01-10 19:35:03 +08:00
BOOL IOCPClient::SendWithSplit(const char* szBuffer, ULONG ulLength, ULONG ulSplitLength)
{
2019-09-07 10:47:50 +08:00
AUTO_TICK(25);
int iReturn = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD><CBB6><EFBFBD>
2019-01-10 19:35:03 +08:00
const char* Travel = szBuffer;
int i = 0;
2019-01-10 19:35:03 +08:00
int ulSended = 0;
const int ulSendRetry = 15;
// <20><><EFBFBD>η<EFBFBD><CEB7><EFBFBD>
for (i = ulLength; i >= ulSplitLength; i -= ulSplitLength)
{
int j = 0;
2019-01-10 19:35:03 +08:00
for (; j < ulSendRetry; ++j)
{
iReturn = send(m_sClientSocket, Travel, ulSplitLength, 0);
if (iReturn > 0)
{
break;
}
}
if (j == ulSendRetry)
{
return FALSE;
}
2019-01-10 19:35:03 +08:00
ulSended += iReturn;
Travel += ulSplitLength;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>
if (i>0) //1024
{
int j = 0;
2019-01-10 19:35:03 +08:00
for (; j < ulSendRetry; j++)
{
iReturn = send(m_sClientSocket, (char*)Travel,i,0);
if (iReturn > 0)
{
break;
}
}
if (j == ulSendRetry)
{
return FALSE;
}
2019-01-10 19:35:03 +08:00
ulSended += iReturn;
}
2019-01-10 19:35:03 +08:00
return (ulSended == ulLength) ? TRUE : FALSE;
}
VOID IOCPClient::Disconnect()
{
std::cout<<"<EFBFBD>Ͽ<EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.\n";
CancelIo((HANDLE)m_sClientSocket);
closesocket(m_sClientSocket);
m_sClientSocket = INVALID_SOCKET;
m_bConnected = FALSE;
}
VOID IOCPClient::RunEventLoop(const BOOL &bCondition)
{
OutputDebugStringA("======> RunEventLoop begin\n");
while (m_bIsRunning && bCondition)
Sleep(200);
OutputDebugStringA("======> RunEventLoop end\n");
}