2024-06-23 17:36:53 +08:00

275 lines
6.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// IOCPServer.h: interface for the CIOCPServer class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_IOCPSERVER_H__75B80E90_FD25_4FFB_B273_0090AA43BBDF__INCLUDED_)
#define AFX_IOCPSERVER_H__75B80E90_FD25_4FFB_B273_0090AA43BBDF__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winsock2.h>
#include <MSTcpIP.h>
#pragma comment(lib,"ws2_32.lib")
#include "Buffer.h"
#include <process.h>
#include <afxtempl.h>
////////////////////////////////////////////////////////////////////
#define NC_CLIENT_CONNECT 0x0001
#define NC_CLIENT_DISCONNECT 0x0002
#define NC_TRANSMIT 0x0003
#define NC_RECEIVE 0x0004
#define NC_RECEIVE_COMPLETE 0x0005 // 完整接收
#define NC_DIALOG_CLOSE 0x0006
class CLock
{
public:
CLock(CRITICAL_SECTION& cs, const CString& strFunc)
{
m_strFunc = strFunc;
m_pcs = &cs;
Lock();
}
~CLock()
{
Unlock();
}
void Unlock()
{
LeaveCriticalSection(m_pcs);
TRACE(_T("LC %d %s\n") , GetCurrentThreadId() , m_strFunc);
}
void Lock()
{
TRACE(_T("EC %d %s\n") , GetCurrentThreadId(), m_strFunc);
EnterCriticalSection(m_pcs);
}
protected:
CRITICAL_SECTION* m_pcs;
CString m_strFunc;
};
enum IOType
{
IOInitialize,
IORead,
IOWrite
};
class OVERLAPPEDPLUS
{
public:
OVERLAPPED m_ol;
IOType m_ioType;
OVERLAPPEDPLUS(IOType ioType) {
ZeroMemory(this, sizeof(OVERLAPPEDPLUS));
m_ioType = ioType;
}
};
struct ClientContext
{
SOCKET m_Socket;
// Store buffers
CBuffer m_WriteBuffer;
CBuffer m_CompressionBuffer; // 接收到的压缩的数据
CBuffer m_DeCompressionBuffer; // 解压后的数据
CBuffer m_ResendWriteBuffer; // 上次发送的数据包,接收失败时重发时用
int m_Dialog[2]; // 放对话框列表用第一个int是类型第二个是CDialog的地址
int m_nTransferProgress;
// Input Elements for Winsock
WSABUF m_wsaInBuffer;
BYTE m_byInBuffer[8192];
// Output elements for Winsock
WSABUF m_wsaOutBuffer;
// HANDLE m_hWriteComplete;
BOOL m_bIsMainSocket; // 是不是主socket
CRITICAL_SECTION m_SndLock;
char szOnlinePass[20];
// 代理映射用到
DWORD dwID;
BYTE m_bProxyConnected;
};
#include "Mapper.h"
typedef void (CALLBACK* NOTIFYPROC)( ClientContext*, UINT nCode);
typedef CList<ClientContext*, ClientContext* > ContextList;
#define FLAG_SIZE 3
class CIOCPServer
{
public:
void DisconnectAll();
CIOCPServer();
virtual ~CIOCPServer();
NOTIFYPROC m_pNotifyProc;
bool Initialize(NOTIFYPROC pNotifyProc, int nMaxConnections, int nPort);
UINT m_nHeartBeatTime;
static unsigned __stdcall ThreadHeartbeat(LPVOID WorkContext);
static unsigned __stdcall ListenThreadProc(LPVOID lpVoid);
static unsigned __stdcall ThreadPoolFunc(LPVOID WorkContext);
CRITICAL_SECTION m_cs;
void PostRecv(ClientContext* pContext);
void Send(ClientContext* pContext, LPBYTE lpData, UINT nSize, BOOL bZlib = FALSE);
void PostSend(ClientContext* pContext);
bool IsRunning();
void Shutdown();
void ResetConnection(ClientContext* pContext);
UINT m_nSendKbps; // 发送即时速度
UINT m_nRecvKbps; // 接受即时速度
UINT m_nMaxConnections; // 最大连接数
SOCKET m_socListen;
protected:
void InitializeClientRead(ClientContext* pContext);
BOOL AssociateSocketWithCompletionPort(SOCKET device, HANDLE hCompletionPort, DWORD dwCompletionKey);
void RemoveStaleClient(ClientContext* pContext, BOOL bGraceful);
void MoveToFreePool(ClientContext *pContext);
ClientContext* AllocateContext(SOCKET clientSocket);
LONG m_nWorkerCnt;
bool m_bInit;
bool m_bDisconnectAll;
BYTE m_bPacketFlag[FLAG_SIZE];
void CloseCompletionPort();
void OnAccept();
bool InitializeIOCP(void);
void Stop();
// 设置保活机制 nKeepTime多长时间没有数据就开始发送心跳包,nKeepInterval每隔多长时间发送一个心跳包 (Vista之前默认5次 之后默认发10次)
BOOL SetKeepAlive( SOCKET Socket, UINT nKeepTime = 10 * 1000, UINT nKeepInterval = 3000 );
ContextList m_listContexts;
ContextList m_listFreePool;
WSAEVENT m_hEvent;
HANDLE m_hKillEvent;
HANDLE m_hThread;
HANDLE m_hCompletionPort;
bool m_bTimeToKill;
LONG m_nKeepLiveTime; // 多长时间没有数据
UINT m_nIntervalTime; // 间隔多少时间发送
DWORD m_dwIndex;
CString GetHostName(SOCKET socket);
BEGIN_IO_MSG_MAP()
IO_MESSAGE_HANDLER(IORead, OnClientReading)
IO_MESSAGE_HANDLER(IOWrite, OnClientWriting)
IO_MESSAGE_HANDLER(IOInitialize, OnClientInitializing)
END_IO_MSG_MAP()
bool OnClientInitializing (ClientContext* pContext, DWORD dwSize = 0);
virtual bool OnClientReading (ClientContext* pContext, DWORD dwSize = 0);
bool OnClientWriting (ClientContext* pContext, DWORD dwSize = 0);
};
char* MyDecode(char *data,int len);
class CIOCPLOCAL :public CIOCPServer
{
public:
void Send(ClientContext* pContext, LPBYTE lpData, UINT nSize)
{
if (pContext == NULL)
return;
CLock cs(pContext->m_SndLock, "Send");
try
{
if (nSize > 0)
{
pContext->m_WriteBuffer.Write(lpData, nSize);
}
PostSend(pContext);
}catch(...){}
}
bool OnClientReading (ClientContext* pContext, DWORD dwIoSize =0)
{
CLock cs(m_cs, "OnClientReading");
try
{
//////////////////////////////////////////////////////////////////////////
static DWORD nLastTick = GetTickCount();
static DWORD nBytes = 0;
nBytes += dwIoSize;
if (GetTickCount() - nLastTick >= 1000)
{
nLastTick = GetTickCount();
InterlockedExchange((LPLONG)&(m_nRecvKbps), nBytes);
nBytes = 0;
}
//////////////////////////////////////////////////////////////////////////
if (dwIoSize == 0)
{
RemoveStaleClient(pContext, FALSE);
return false;
}
// Add the message to out message
// Dont forget there could be a partial, 1, 1 or more + partial mesages
pContext->m_CompressionBuffer.ClearBuffer();
BYTE bToken = COMMAND_PROXY_DATA;
pContext->m_CompressionBuffer.Write(&bToken,sizeof(bToken));
pContext->m_CompressionBuffer.Write((LPBYTE)&pContext->dwID ,sizeof(DWORD));
pContext->m_CompressionBuffer.Write(pContext->m_byInBuffer,dwIoSize);
m_pNotifyProc(pContext, NC_RECEIVE);
PostRecv(pContext);
}
catch(...)
{
TRACE(_T("CIOCPLOCAL::OnClientReading Exception!"));
}
return true;
}
};
#endif // !defined(AFX_IOCPSERVER_H__75B80E90_FD25_4FFB_B273_0090AA43BBDF__INCLUDED_)