📄 udiiocptcpserver.pas
字号:
{$ENDIF}
FWinSocket.CloseWinSocket(FDIBuffer.m_Socket);
Result := FALSE;
end
else
begin
//是否安全连接
if not IsSecurityConnection(FDIBuffer) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('OnWSAAcceptEx m_Socket = INVALID_SOCKET, 关闭客户端Socket连接.');
{$ENDIF}
FWinSocket.CloseWinSocket(FDIBuffer.m_Socket);
Result := FALSE;
end
else
begin
//1.设置AcceptEx的Socket为ListenSocket状态。
//2.生成客户端上下文(投递Recv I/O操作)。
if FWinSocket.ChangeSocketModeAccept(FDIBuffer.m_Socket, m_sListen) then
begin
Result := AssociateIncomingClientWithContext(FDIBuffer);
{$IFDEF _ICOP_DEBUGERR}
if Result = FALSE then AppendErrorLogMessage('AssociateIncomingClientWithContext is Failer.');
{$ENDIF}
end
else
begin
Result :=FALSE;
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('ChangeSocketModeAccept is Failer.');
{$ENDIF}
end;
end;
end;
//Accept请求完成,移出AcceptEx队列, 回收Buffer
m_MapAcceptExBuffer.RemoveDIBuffer(FDIBuffer);
m_PoolBuffer.ReleaseBufferToPool(FDIBuffer);
//通知监听线程继续再投递一个Accept请求
InterlockedIncrement(m_iIOCPPostAccepts);
//m_hPostAcceptEvent事件,I/O的线程连接新用户,投递维持一定AcceptEx数量
SetEvent(m_hPostAcceptEvent);
Result := TRUE;
end;
function TDIIocpTcpServer.AssociateIncomingClientWithContext(m_Socket: TSocket): Boolean;
var
bVal: LongBool;
FClientContext: TDIClientContext;
begin
//检查套接字
if (m_Socket = INVALID_SOCKET) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('m_Scket = INVALID_SOCKET, AssociateIncomingClientWithContext退出: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//系统退出或设置未连接状态,则关闭客户端SOCKET
if (m_bShutDown) or (not m_bAcceptConnections) then begin
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('m_bShutDown OR not m_bAcceptConnections, 关闭客户端连接.');
{$ENDIF}
FWinSocket.CloseWinSocket(m_Socket);
Result := FALSE;
Exit;
end;
//是否超过最大连接数:
FMapClientContextLock.Lock;
if( m_iNumberOfActiveConnections >= m_iMaxNumConnections ) then begin
FMapClientContextLock.UnLock;
{$IFDEF _ICOP_DEBUG}
AppendLogMessage(Format('客户端已经达到最大连接数: %d, 关闭客户端连接.', [m_iMaxNumConnections]));
{$ENDIF}
FWinSocket.CloseWinSocket(m_Socket);
Result := FALSE;
Exit;
end;
FMapClientContextLock.UnLock;
//从空闲池中分配一个上下文
FClientContext := m_PoolClientContext.AllocateFreeClientContextFromPool;
if not Assigned(FClientContext) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('FPoolClientContext.AllocateFreeClientContextFromPool错误: %d.', [WSAGetLastError()]));
{$ENDIF}
FWinSocket.CloseWinSocket(m_Socket);
Result := FALSE;
Exit;
end;
//设置Socket, KeyID, 得到客户端IP地址
FClientContext.FSocket := m_Socket;
FClientContext.m_KeyID := FClientContext.FSocket;
//禁止nagle算法
bVal := TRUE;
if not FWinSocket.SetSocketNagle(FClientContext.m_Socket, bVal) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('setsockopt(禁止nagle算法) 错误: %d.',[WSAGetLastError()]));
{$ENDIF}
//回收上下文
m_PoolClientContext.ReleaseClientContextToPool(FClientContext);
Result := FALSE;
Exit;
end;
//客户上下文插入上下文管理中。
FMapClientContextLock.Lock;
if FMapClientContext.AddDIClientContext( FClientContext ) then begin
FMapClientContextLock.UnLock;
//关联完成端口
if m_IOCompletionPort.AssociateSocketWithCompletionPort( FClientContext.FSocket,
DWORD(Pointer(FClientContext)) ) then
begin
//连接数加1
InterlockedIncrement(m_iNumberOfActiveConnections);
//性能分析器 增加完成端口中连接数量
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddActiveConn;
{$ENDIF}
//触发客户端连接事件
if Assigned(OnNewSocketEvent) then OnNewSocketEvent(FClientContext);
//投递Recv I/O 操作,接收客户端数据。
PostWSARecv(FClientContext);
Result :=TRUE;
end
else
begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('m_IOCompletionPort.AssociateSocketWithCompletionPort失败: %d.',[WSAGetLastError()]));
{$ENDIF}
//安全关闭客户端套接字
FWinSocket.CloseWinSocket(m_Socket);
//移出上下文Map, 释放上下文
FMapClientContextLock.Lock;
FMapClientContext.RemoveDIClientContext(FClientContext);
FMapClientContextLock.UnLock;
m_PoolClientContext.ReleaseClientContextToPool(FClientContext);
Result := FALSE;
Exit;
end;
end
else
begin
FMapClientContextLock.UnLock;
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('m_MapClientContext.AddClientContext失败: %d.',[WSAGetLastError()]));
{$ENDIF}
//安全关闭客户端套接字, 释放上下文
FWinSocket.CloseWinSocket(m_Socket);
m_PoolClientContext.ReleaseClientContextToPool(FClientContext);
Result := FALSE;
Exit;
end;
end;
function TDIIocpTcpServer.AssociateIncomingClientWithContext(FDIBuffer: TDIBuffer): Boolean;
var
bVal: LongBool;
LocalAddrLen, RemoteAddrLen: Integer;
FClientContext: TDIClientContext;
begin
//检查套接字
if (FDIBuffer.m_Socket = INVALID_SOCKET) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('m_Scket = INVALID_SOCKET, AssociateIncomingClientWithContext退出: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//系统退出或设置未连接状态,则关闭客户端SOCKET
if (m_bShutDown) or (not m_bAcceptConnections) then begin
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('m_bShutDown OR not m_bAcceptConnections, 关闭客户端连接.');
{$ENDIF}
FWinSocket.CloseWinSocket(FDIBuffer.m_Socket);
Result := FALSE;
Exit;
end;
//是否超过最大连接数:
FMapClientContextLock.Lock;
if( m_iNumberOfActiveConnections >= m_iMaxNumConnections ) then begin
FMapClientContextLock.UnLock;
{$IFDEF _ICOP_DEBUG}
AppendLogMessage(Format('客户端已经达到最大连接数: %d, 关闭客户端连接.', [m_iMaxNumConnections]));
{$ENDIF}
FWinSocket.CloseWinSocket(FDIBuffer.m_Socket);
Result := FALSE;
Exit;
end;
FMapClientContextLock.UnLock;
//从空闲池中分配一个上下文
FClientContext := m_PoolClientContext.AllocateFreeClientContextFromPool;
if not Assigned(FClientContext) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('FPoolClientContext.AllocateFreeClientContextFromPool错误: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//设置Socket, KeyID, 得到客户端IP地址
FClientContext.FSocket := FDIBuffer.m_Socket;
FClientContext.m_KeyID := FClientContext.FSocket;
//获取客户端IP地址
m_lpfnGetAcceptExSockaddrs( FDIBuffer.GetBuffer,
0,
sizeof(TSockAddrIn)+16,
sizeof(TSockAddrIn)+16,
FClientContext.FLocalAddr,
LocalAddrLen,
FClientContext.FRemoteAddr,
RemoteAddrLen );
FClientContext.FRemoteIP := FWinSocket.GetRemoteIPAddr(FClientContext.FRemoteAddr^);
//设置心跳参数, 次数0
FClientContext.SetHeartBeatParam(GetTickCount);
//禁止nagle算法
bVal := TRUE;
if not FWinSocket.SetSocketNagle(FClientContext.m_Socket, bVal) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('setsockopt(禁止nagle算法) 错误: %d.',[WSAGetLastError()]));
{$ENDIF}
//回收上下文
m_PoolClientContext.ReleaseClientContextToPool(FClientContext);
Result := FALSE;
Exit;
end;
//客户上下文插入上下文管理中。
FMapClientContextLock.Lock;
if FMapClientContext.AddDIClientContext( FClientContext ) then begin
FMapClientContextLock.UnLock;
//关联完成端口
if m_IOCompletionPort.AssociateSocketWithCompletionPort( FClientContext.FSocket,
DWORD(Pointer(FClientContext)) ) then
begin
//连接数加1
InterlockedIncrement(m_iNumberOfActiveConnections);
//性能分析器 增加完成端口中连接数量
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddActiveConn;
{$ENDIF}
//触发客户端连接事件
if Assigned(OnNewSocketEvent) then OnNewSocketEvent(FClientContext);
//投递Recv I/O 操作,接收客户端数据。
PostWSARecv(FClientContext);
Result :=TRUE;
end
else
begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('m_IOCompletionPort.AssociateSocketWithCompletionPort失败: %d.',[WSAGetLastError()]));
{$ENDIF}
//安全关闭客户端套接字
FWinSocket.CloseWinSocket(FClientContext.m_Socket);
//移出上下文Map, 释放上下文
FMapClientContextLock.Lock;
FMapClientContext.RemoveDIClientContext(FClientContext);
FMapClientContextLock.UnLock;
m_PoolClientContext.ReleaseClientContextToPool(FClientContext);
Result := FALSE;
end;
end
else
begin
FMapClientContextLock.UnLock;
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('m_MapClientContext.AddClientContext失败: %d.',[WSAGetLastError()]));
{$ENDIF}
//安全关闭客户端套接字,释放上下文
FWinSocket.CloseWinSocket(FClientContext.m_socket);
m_PoolClientContext.ReleaseClientContextToPool(FClientContext);
Result := FALSE;
end;
end;
function TDIIocpTcpServer.PostWSARecv(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.RecvBuffer.InitBuffer;
FClientContext.RecvBuffer.SetOperation(IOWSARecv);
FClientContext.RecvBuffer.SetupRead;
dwIOSize := 0;
dwFlags := 0;
nRet := WinSock2.WSARecv( FClientContext.FSocket,
@FClientContext.RecvBuffer.FWSABuf,
1,
dwIOSize,
dwFlags,
@FClientContext.RecvBuffer.PerHandleData,
nil );
if( ( nRet = SOCKET_ERROR ) and ( WSAGetLastError() <> WSA_IO_PENDING ) ) then begin
FClientContext.FContextLock.UnLock;
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('WSARecv DisconnectClient, key is:'+IntToStr(FClientContext.m_KeyID));
{$ENDIF}
if( ( nRet = SOCKET_ERROR ) and ( WSAGetLastError() = WSAEWOULDBLOCK ) ) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('WSARecv 缓冲区满, key is:'+IntToStr(FClientContext.m_KeyID));
{$ENDIF}
end;
//投递
PostWSACloseSocket(FClientContext);
Result := FALSE;
Exit;
end;
//加一 接受加1
FClientContext.EnterIOLoop(IOWSARecv);
Result := TRUE;
end;
//解锁处理
FClientContext.FContextLock.UnLock;
//性能分析器 增加完成端口中Recv I/O数量
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddIOCPRecv;
{$ENDIF}
end;
end;
function TDIIocpTcpServer.OnWSARecv(FClientContext: TDIClientContext; FRecvBuffer: TDIBuffer; dwIoSize: DWORD): Boolean;
begin
if (FClientContext<> nil) then begin
//心跳处理
FClientContext.FContextLock.Lock;
FRecvBuffer.SetUsed(dwIoSize);
FClientContext.SetHeartBeatParam(GetTickCount);
FClientContext.FContextLock.UnLock;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -