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

📄 udiiocptcpserver.pas

📁 楠楠写的DBiocp例子都是源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:
    {$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 + -