📄 udiiocptcpserver.pas
字号:
if Assigned(OnRecvCompletedEvent) then
OnRecvCompletedEvent(FClientContext, FRecvBuffer, dwIoSize);
end;
Result := TRUE;
end;
function TDIIocpTcpServer.PostWSASend(FClientContext: TDIClientContext): Boolean;
var
nRet: integer;
dwIOSize: DWORD;
dwFlags: DWORD;
begin
Result := FALSE;
if (FClientContext<>nil) then begin
FClientContext.FContextLock.Lock;
if (not FClientContext.FPostCloseSocket) and (not m_bShutDown) then begin
FClientContext.SendBuffer.SetOperation(IOWSASend);
FClientContext.SendBuffer.SetupWrite;
dwIOSize := 0;
dwFlags := 0;
nRet := WinSock2.WSASend( FClientContext.FSocket,
@FClientContext.SendBuffer.FWSABuf,
1,
dwIOSize,
dwFlags,
@FClientContext.SendBuffer.PerHandleData,
nil );
if( ( nRet = SOCKET_ERROR ) and ( WSAGetLastError() <> WSA_IO_PENDING ) ) then begin
FClientContext.FContextLock.UnLock;
if( ( nRet = SOCKET_ERROR ) and ( WSAGetLastError() = WSAEWOULDBLOCK ) ) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('WSASend 缓冲区满, key is:'+IntToStr(FClientContext.m_KeyID));
{$ENDIF}
end;
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('WSASend DisconnectClient, key is:'+IntToStr(FClientContext.m_KeyID));
{$ENDIF}
//投递
PostWSACloseSocket(FClientContext);
Result := FALSE;
Exit;
end;
//加一 发送加1
FClientContext.EnterIOLoop(IOWSASend);
Result := TRUE;
end;
FClientContext.FContextLock.UnLock;
//性能分析器 增加完成端口中Send I/O数量
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddIOCPSend;
{$ENDIF}
end;
end;
function TDIIocpTcpServer.OnWSASend(FClientContext: TDIClientContext; FSendBuffer: TDIBuffer; dwIoSize: DWORD): Boolean;
begin
if (FClientContext<> nil) then begin
//心跳处理
FClientContext.FContextLock.Lock;
FSendBuffer.SetUsed(dwIoSize);
FClientContext.SetHeartBeatParam(GetTickCount);
FClientContext.FContextLock.UnLock;
if Assigned(OnSendCompletedEvent) then
OnSendCompletedEvent(FClientContext, FSendBuffer, dwIoSize);
end;
Result := TRUE;
end;
function TDIIocpTcpServer.PostWSACloseSocket(FClientContext: TDIClientContext): Boolean;
var
bPostCloseSocket: Boolean;
begin
Result := FALSE;
if (FClientContext<>nil) then begin
FClientContext.FContextLock.Lock;
bPostCloseSocket := FClientContext.FPostCloseSocket;
//如果未投递
if not bPostCloseSocket then begin
FClientContext.SetupOvlpClose;
if LongBool(m_IOCompletionPort.PostIOCompletionStatus( DWORD(Pointer(FClientContext)),
@FClientContext.FCloseOverlap,
0)) = False
then
begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('TDIIocpTcpServer.PostWSACloseSocket失败: %d.',[WSAGetLastError()]));
{$ENDIF}
FClientContext.FPostCloseSocket := FALSE;
FClientContext.FContextLock.UnLock;
Result := FALSE;
Exit;
end;
FClientContext.FPostCloseSocket := TRUE;
//加一 接受加1
FClientContext.EnterIOLoop(IOWSACloseSocket);
FClientContext.FContextLock.UnLock;
Result := TRUE;
//性能分析器 增加完成端口中CloseSocket I/O数量
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddIOCPCloseSocke;
_DIMonitor.AddPostClose;
{$ENDIF}
// {$IFDEF _ICOP_DEBUGERR}
// AppendErrorLogMessage(Format('TDIIocpTcpServer.PostWSACloseSocket成功: %d.',[FClientContext.m_KeyID]));
// {$ENDIF}
end;
end;
end;
//踢出死连接
procedure TDIIocpTcpServer.KillDeadClientSocket;
var
m_bDisconnect: Boolean;
BeginTime: DWORD;
EndTime: DWORD;
m_iTimeOut: Real;
m_pFreeClientContext: TDIClientContext;
m_pNextClientContext: TDIClientContext;
begin
//10秒检查一次
if (GetTickCount-m_dLastTime> 10*1000) then begin
try
//快速退出
if m_bShutDown then Exit;
FMapClientContextLock.Lock;
//取单链表头
m_pFreeClientContext := FMapClientContext.FClientContextList;
m_pNextClientContext := nil;
while (m_pFreeClientContext<> nil) do begin
m_pNextClientContext := m_pFreeClientContext.m_pNext;
m_pFreeClientContext.FContextLock.Lock;
BeginTime := m_pFreeClientContext.FHeartBeatParam.m_BeginTime;
m_bDisconnect := m_pFreeClientContext.FSocket <> INVALID_SOCKET;
m_pFreeClientContext.FContextLock.UnLock;
EndTime := GetTickCount;
//次数
m_iTimeOut := (EndTime -BeginTime) / MAX_HEARTBEAT_TIME;
if (m_iTimeOut>MAX_HEARTBEAT_COUT) and m_bDisconnect then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('KillDeadClientSocket: %d.',[m_pFreeClientContext.m_KeyID]));
{$ENDIF}
//断开客户端
DisconnectClient(m_pFreeClientContext);
end;
m_pFreeClientContext := m_pNextClientContext;
end;
finally
FMapClientContextLock.UnLock;
end;
//重新赋值
m_dLastTime := GetTickCount;
end;
end;
function TDIIocpTcpServer.StartServe( nPort: Integer;
iMaxNumConnections: DWORD;
iMaxNumberOfFreeContext: DWORD;
iMaxNumberOfFreeBuffer: DWORD;
StartType: TServerStartType): Boolean;
var
bRet: LongBool;
begin
if (m_bServerStarted) then begin
Result := False;
Exit;
end;
m_ServerType := StartType;
if m_ServerType = IOServerStart then
AppendDisplayMsg(Format('IOCP服务器端启动, 系统版本号: %s.', [IOCP_TCPSERVER_VERSION]))
else
AppendDisplayMsg(Format('IOCP客户端启动, 系统版本号: %s.', [IOCP_TCPSERVER_VERSION]));
m_nPort := nPort;
//设置m_bShutDown, 设置状态,允许客户端连接
m_bShutDown := FALSE;
m_iNumberOfActiveConnections := 0; //当前客户端连接个数置零
m_nInitPostAcceptEx := 100; //初次提交的AccpetEx I/O数
m_iMaxNumConnections := iMaxNumConnections; //允许最多客户端连接个数
m_iMaxNumberOfFreeContext := iMaxNumberOfFreeContext; //空闲上下文池允许的最大数
m_iMaxNumberOfFreeBuffer := iMaxNumberOfFreeBuffer; //空闲Buufer池允许的最大数
//设置最大上下文上限, 超过该值,物理释放上下文
FPoolClientContext.SetMaxFreeClientContext(m_iMaxNumberOfFreeContext);
//设置最大Buffer上限, 超过该值,物理释放Buffer
FPoolBuffer.SetMaxFreeBuffer(m_iMaxNumberOfFreeBuffer);
//关闭IOCP性能监视器
{$IFDEF _IOCP_MONITOR}
_DIMonitor.StartMonitor;
AppendLogMessage('IOCP性能监视器启动成功.');
{$ENDIF}
if m_ServerType = IOServerStart then begin
//服务器端启动侦听
bRet := ListnerStart();
if(bRet) then
AppendDisplayMsg('服务器端启动套接字侦听.')
else
begin
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('系统异常错误,服务器端侦听线程启动失败.');
{$ENDIF}
Result := FALSE;
Exit;
end;
end;
if m_ServerType = IOServerStart then begin
if (bRet) then begin
m_bServerStarted := TRUE;
AppendDisplayMsg(Format('IOCP服务器端侦听地址: %s, 端口号:%d.', [FWinSocket.GetHostIPAddr(), m_nPort]));
AppendDisplayMsg('IOCP服务器端启动成功.');
end;
end
else
begin
m_bServerStarted := TRUE;
m_bAcceptConnections := TRUE;
AppendDisplayMsg('IOCP客户端启动启动成功.');
end;
Result := TRUE;
end;
procedure TDIIocpTcpServer.ProcessFreeMemory;
{$IFDEF _ICOP_DEBUG}
var
m_pFreeClientContext: TDIClientContext;
m_pNextClientContext: TDIClientContext;
{$ENDIF}
begin
//释放上下文回收池
{$IFDEF _ICOP_DEBUG}
AppendLogMessage( 'FPoolClientContext.FreeClientContexts上下文回收池释放内存, 个数:'
+IntToStr(FPoolClientContext.GetClientContextCount) );
{$ENDIF}
FPoolClientContext.FreeClientContexts;
{$IFDEF _ICOP_DEBUG}
try
FMapClientContextLock.Lock;
//取单链表头
m_pFreeClientContext := FMapClientContext.FClientContextList;
m_pNextClientContext := nil;
while (m_pFreeClientContext<> nil) do begin
m_pNextClientContext := m_pFreeClientContext.m_pNext;
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('+ProcessFreeMemory关闭客户端套接字, Socket: '+IntToStr(m_pFreeClientContext.m_KeyID));
{$ENDIF}
m_pFreeClientContext := m_pNextClientContext;
end;
finally
FMapClientContextLock.UnLock;
end;
{$ENDIF}
//释放上下文管理
FMapClientContextLock.Lock;
{$IFDEF _ICOP_DEBUG}
AppendLogMessage( 'FMapClientContext.FreeClientContexts上下文管理释放内存, 个数:'
+IntToStr(FMapClientContext.GetClientContextCount) );
{$ENDIF}
FMapClientContext.FreeClientContexts;
FMapClientContextLock.UnLock;
//释放内存回收池
{$IFDEF _ICOP_DEBUG}
AppendLogMessage( 'FPoolBuffer.FreeBuffers内存回收池释放内存, 个数:'
+IntToStr(m_PoolBuffer.GetBufferCount) );
{$ENDIF}
m_PoolBuffer.FreeBuffers;
//释放AcceptEx内存管理
{$IFDEF _ICOP_DEBUG}
AppendLogMessage( 'FMapAcceptExBuffer.FreeBuffers内存AcceptEx管理释放内存, 个数:'
+IntToStr(m_MapAcceptExBuffer.GetBufferCount) );
{$ENDIF}
m_MapAcceptExBuffer.FreeBuffers;
end;
procedure TDIIocpTcpServer.StopServer;
begin
if (m_bServerStarted) then begin
//是否允许客户端连接
m_bAcceptConnections := FALSE;
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('设置连接状态m_bAcceptConnections := FALSE.');
{$ENDIF}
//关闭所有连接
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('关闭所有客户端DisconnectAllClient成功.');
{$ENDIF}
DisconnectAllClient;
Sleep(0);
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('关闭所有AcceptEx DisconnectAllBufferSocket成功.');
{$ENDIF}
DisconnectAllBufferSocket;
Sleep(0);
//设置关闭
m_bShutDown := TRUE;
if m_ServerType = IOServerStart then begin
//停止侦听线程
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('WaitForSingleObject m_hListnerThread.');
{$ENDIF}
SetEvent(m_hShutdownEvent);
Sleep(0);
WaitForSingleObject(m_hListnerThread.Handle, INFINITE);
m_hListnerThread.Free;
CloseHandle(m_hShutdownEvent);
m_hShutdownEvent := INVALID_HANDLE_VALUE;
CloseHandle(m_hListnerThreadEvent);
m_hListnerThreadEvent := INVALID_HANDLE_VALUE;
CloseHandle(m_hPostAcceptEvent);
m_hPostAcceptEvent := INVALID_HANDLE_VALUE;
//关闭侦听套接字
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('关闭侦听套接字.');
{$ENDIF}
WinSock2.shutdown(m_sListen, SD_BOTH);
FWinSocket.CloseWinSocket(m_sListen);
Sleep(0);
end;
//关闭IOCP性能监视器
{$IFDEF _IOCP_MONITOR}
_DIMonitor.StopMonitor;
AppendLogMessage('IOCP性能监视器关闭成功.');
{$ENDIF}
m_bServerStarted := FALSE;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -