📄 udiiocpudpserver.pas
字号:
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 TDIIocpUdpServer.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;
if Assigned(OnRecvCompletedEvent) then
OnRecvCompletedEvent(FClientContext, FRecvBuffer, dwIoSize);
end;
Result := TRUE;
end;
function TDIIocpUdpServer.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 TDIIocpUdpServer.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 TDIIocpUdpServer.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('TDIIocpUdpServer.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('TDIIocpUdpServer.PostWSACloseSocket成功: %d.',[FClientContext.m_KeyID]));
// {$ENDIF}
end;
end;
end;
//踢出死连接
procedure TDIIocpUdpServer.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 TDIIocpUdpServer.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_UDPSERVER_VERSION]))
else
AppendDisplayMsg(Format('IOCP客户端启动, 系统版本号: %s.', [IOCP_UDPSERVER_VERSION]));
m_nPort := nPort;
//设置m_bShutDown, 设置状态,允许客户端连接
m_bShutDown := FALSE;
m_iNumberOfActiveConnections := 0; //当前客户端连接个数置零
m_iMaxNumConnections := iMaxNumConnections; //允许最多客户端连接个数
m_iMaxNumberOfFreeContext := iMaxNumberOfFreeContext; //空闲上下文池允许的最大数
m_iMaxNumberOfFreeBuffer := iMaxNumberOfFreeBuffer; //空闲Buufer池允许的最大数
//设置最大上下文上限, 超过该值,物理释放上下文
FPoolClientContext.SetMaxFreeClientContext(m_iMaxNumberOfFreeContext);
//关闭IOCP性能监视器
{$IFDEF _IOCP_MONITOR}
_DIMonitor.StartMonitor;
AppendLogMessage('IOCP性能监视器启动成功.');
{$ENDIF}
if not FWinSocket.CreateUDPOverlapSocket(m_sListen) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('创建 Socket套按字失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//绑定套接字
if not FWinSocket.BindSocket(m_sListen, m_nPort) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('绑定套接字 bind() 调用失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//将监听套节字关联到完成端口,注意,这里为它传递的CompletionKey为0
m_IOCompletionPort.AssociateSocketWithCompletionPort(m_sListen, DWORD(0));
if m_ServerType = IOServerStart then begin
m_bServerStarted := TRUE;
AppendDisplayMsg(Format('IOCP服务器端侦听地址: %s, 端口号:%d.', [FWinSocket.GetHostIPAddr(), m_nPort]));
AppendDisplayMsg('IOCP服务器端启动成功.');
end
else
begin
m_bServerStarted := TRUE;
m_bAcceptConnections := TRUE;
AppendDisplayMsg('IOCP客户端启动启动成功.');
end;
Result := TRUE;
end;
procedure TDIIocpUdpServer.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;
end;
procedure TDIIocpUdpServer.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);
//设置关闭
m_bShutDown := TRUE;
WinSock2.shutdown(m_sListen, SD_BOTH);
FWinSocket.CloseWinSocket(m_sListen);
Sleep(0);
//关闭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 + -