⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udiiocptcpserver.pas

📁 楠楠写的DBiocp例子都是源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:

    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 + -