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

📄 udiiocptcpserver.pas

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

procedure TDIIocpTcpServer.ListnerThreadProc;
var
  i, nRet: Integer;
  nIndex, m_nPostAccepts: DWORD;
  pBuffer: TDIBuffer;
  iRunTime: Integer;
  Events: TWSANetworkEvents;
begin
  //投递AcceptEx I/O
  for i:=1 to m_nInitPostAcceptEx do begin
    pBuffer := nil;

    pBuffer := m_PoolBuffer.AllocateFreeBufferFromPool;
    if (pBuffer = nil) then begin

      {$IFDEF _ICOP_DEBUGERR}
          AppendErrorLogMessage('AllocateFreeBufferFromPool错误, ListnerThreadProc线程退出.');
      {$ENDIF}
      Exit;
    end
    else
    begin
      //加入上下文中
      m_MapAcceptExBuffer.AddDIBuffer(pBuffer);
      if not PostWSAAcceptEx(pBuffer) then begin
      
        {$IFDEF _ICOP_DEBUGERR}
            AppendErrorLogMessage('PostWSAAcceptEx投递Accept I/O错误, ListnerThreadProc线程退出.');
        {$ENDIF}
        Exit;
      end;
    end;
  end;

  iRunTime := 0;
  while (TRUE) do
  begin
    //等网络事件m_hPostAcceptEvent事件和m_hListnerThreadEvent事件
    //停止服务内核对象10秒,检查一次, 快速退出
    nIndex := WSAWaitForMultipleEvents(3, @m_hWaitEventList[0], FALSE, 10000, FALSE);
    if (nIndex = WSA_WAIT_FAILED) then begin

      {$IFDEF _ICOP_DEBUGERR}
          AppendErrorLogMessage('WSA_WAIT_FAILED错误, ListnerThreadProc线程退出.');
      {$ENDIF}
      Break;
    end;

    //快速退出
    if m_bShutDown then Exit;

    //超时踢出死连接
    if (nIndex = WSA_WAIT_TIMEOUT) then begin
        KillDeadClientSocket
    end
    else
    begin
      nIndex := nIndex - WAIT_OBJECT_0;
      //停止服务内核对象         
      if (nIndex = 0 ) then begin

        {$IFDEF _ICOP_DEBUG}
            AppendLogMessage('停止服务内核对象事件, ListnerThreadProc线程退出消息.');
        {$ENDIF}
        Break;
      end
      //m_hPostAcceptEvent事件,I/O的线程连接新用户,投递维持一定AcceptEx数量
      else if (nIndex = 1 ) then begin
              m_nPostAccepts := InterlockedExchange(m_iIOCPPostAccepts, 0);
           end
           else
           begin
             if (nIndex = 2 ) then begin
               nRet := WSAEnumNetworkEvents( m_sListen,
                                             m_hWaitEventList[nIndex],
                                             @Events );
               if (nRet = SOCKET_ERROR) then begin
               
                 {$IFDEF _ICOP_DEBUGERR}
                     AppendErrorLogMessage(Format('异常WSAEnumNetworkEvents错误%d, ListnerThreadProc线程退出.', [WSAGetLastError()]));
                 {$ENDIF}
                 Break;
               end;

               if (Events.lNetworkEvents = FD_ACCEPT) then begin
                 //多次检查m_bShutDown状态,以便退出线程
                 if ( (Events.iErrorCode[FD_ACCEPT_BIT] = 0) and
                      (m_bAcceptConnections) and
                      (not m_bShutDown) ) then begin
                   m_nPostAccepts := 50;  //增加的个数,这里设为50个
                 end
                 else
                 begin

                   {$IFDEF _ICOP_DEBUGERR}
                       AppendErrorLogMessage(Format('异常WSAEnumNetworkEvents错误%d, ListnerThreadProc线程退出.', [WSAGetLastError()]));
                   {$ENDIF}
                   Break;
                 end;
               end;
             end;
           end;

      //继续投递一定数量的AcceptEx I/O
      if m_bAcceptConnections  then begin
        for i:=1 to m_nPostAccepts do begin
          pBuffer := nil;
          pBuffer := m_PoolBuffer.AllocateFreeBufferFromPool;
          if (pBuffer = nil) then begin

            {$IFDEF _ICOP_DEBUGERR}
                AppendErrorLogMessage('AllocateFreeBufferFromPool错误, ListnerThreadProc线程退出.');
            {$ENDIF}
            Exit;
          end
          else
          begin
            //加入上下文中
            m_MapAcceptExBuffer.AddDIBuffer(pBuffer);
            if not PostWSAAcceptEx(pBuffer) then begin

              {$IFDEF _ICOP_DEBUGERR}
                  AppendErrorLogMessage('PostWSAAcceptEx投递Accept I/O错误, ListnerThreadProc线程退出.');
              {$ENDIF}
              Exit;
            end;
          end;
        end;
      end;
    end;
  end;

  {$IFDEF _ICOP_DEBUG}
      AppendLogMessage('ListnerThreadProc线程退出消息.');
  {$ENDIF}
end;

function TDIIocpTcpServer.ListnerStart: Boolean;
var
  nRet: Integer;
begin
  if not FWinSocket.CreateTCPOverlapSocket(m_sListen) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('创建 Socket监听套按字失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    Result := FALSE;
    Exit;
  end;

  if not FWinSocket.SetSocketReUseAddr(m_sListen) then begin
  
    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('设置端口复用setsockopt(SO_EXCLUSIVEADDRUSE) 创建失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    FWinSocket.CloseWinSocket(m_sListen);
    Result := FALSE;
    Exit;
  end;

  //设置Wait线程内核对象列表(AcceptEx线程)
  SetLength(m_hWaitEventList, 3);


  //停止服务内核对象, 加入WaitThread事件列表
  m_hShutdownEvent := CreateEvent(nil, FALSE, FALSE, nil);
  if (m_hShutdownEvent = WSA_INVALID_EVENT) then begin

      {$IFDEF _ICOP_DEBUGERR}
          AppendErrorLogMessage(Format('停止服务内核对象WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
      {$ENDIF}
      FWinSocket.CloseWinSocket(m_sListen);
      WSACloseEvent(m_hShutdownEvent);
      Result := False;
      Exit;
    end;
   m_hWaitEventList[0] := m_hShutdownEvent;


  //投递Accept I/O事件内核对象, 加入WaitThread事件列表
	m_hPostAcceptEvent := CreateEvent(nil, FALSE, FALSE, nil);
  if (m_hPostAcceptEvent = WSA_INVALID_EVENT) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('投递Accept I/O事件内核对象WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    WSACloseEvent(m_hPostAcceptEvent);
    FWinSocket.CloseWinSocket(m_sListen);
	  Result := False;
    Exit;
  end;
	m_hWaitEventList[1] := m_hPostAcceptEvent;
  

  //WSAEventSelectI/O模型处理Accept事件, 加入WaitThread事件列表
  m_hListnerThreadEvent := WSACreateEvent;
  if (m_hListnerThreadEvent = WSA_INVALID_EVENT) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('WSAEventSelectI/O模型处理Accept事件WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    WSACloseEvent(m_hListnerThreadEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    FWinSocket.CloseWinSocket(m_sListen);
    Result := FALSE;
    Exit
  end;
  m_hWaitEventList[2] := m_hListnerThreadEvent;


  //注册FD_ACCEPT事件。
	//如果投递的AcceptEx I/O不够,线程会接收到FD_ACCEPT网络事件,说明应该投递更多的AcceptEx I/O
  nRet := WSAEventSelect(m_sListen, m_hListnerThreadEvent, FD_ACCEPT);
  if (nRet = SOCKET_ERROR) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('注册FD_ACCEPT事件 WSAAsyncSelect()调用失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    WSACloseEvent(m_hListnerThreadEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    FWinSocket.CloseWinSocket(m_sListen);
    Result := FALSE;
    Exit;
  end;


  //加载扩展函数AcceptEx
  if not FWinSocket.LoadAcceptEx(m_sListen, m_lpfnAcceptEx) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('WSAIoctl 加载AcceptEx函数失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    WSACloseEvent(m_hListnerThreadEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    FWinSocket.CloseWinSocket(m_sListen);
    Result := FALSE;
    Exit;
  end;
  

  //加载扩展函数GetAcceptExSockaddrs
  if not FWinSocket.LoadAcceptExSockaddrs(m_sListen, m_lpfnGetAcceptExSockaddrs) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('WSAIoctl 加载GetAcceptExSockaddrs函数失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
		WSACloseEvent(m_hListnerThreadEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    FWinSocket.CloseWinSocket(m_sListen);
    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;


  //侦听
  if not FWinSocket.ListenSocket(m_sListen) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('侦听套接字listen() 调用失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    Result := FALSE;
    Exit;
  end;


  //将监听套节字关联到完成端口,注意,这里为它传递的CompletionKey为0
  m_IOCompletionPort.AssociateSocketWithCompletionPort(m_sListen, DWORD(0));


  //创建侦听线程
  m_hListnerThread := TDIListnerThread.Create(self);
  if (m_hListnerThread = nil) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('创建ListnerThreadProc线程错误: %d.', [WSAGetLastError()]));
    {$ENDIF}
    WSACloseEvent(m_hListnerThreadEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    FWinSocket.CloseWinSocket(m_sListen);
    Result := FALSE;
    Exit;
  end;
  m_hListnerThread.Run;

  
  //调置允许连接 计算超时时间
  m_bAcceptConnections := TRUE;
  m_dLastTime := GetTickCount;
	Result := TRUE;
end;

function TDIIocpTcpServer.PostWSAAcceptEx(AcceptExBuffer: TDIBuffer): Boolean;
var
  FAcceptSocket: TSocket;
  FAcceptReceived: Cardinal;
  nRetVal: LongBool;
begin
  if not Assigned(AcceptExBuffer) then begin
    Result := False;
    Exit;
  end;

  //创建Socket
  if not FWinSocket.CreateTCPOverlapSocket(FAcceptSocket) then begin
  
    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('PostWSAAcceptEx 创建监听套按字失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    Result := FALSE;
    Exit;
  end;

  //设置标志
  FAcceptReceived := 0;
  AcceptExBuffer.SetOperation(IOWSAAcceptEx);
  AcceptExBuffer.SetupRead;
  AcceptExBuffer.m_Socket := FAcceptSocket;
  nRetVal := m_lpfnAcceptEx( m_sListen,
                             AcceptExBuffer.m_Socket,
                             AcceptExBuffer.GetBuffer,
                             0,
                             sizeof(TSockAddrIn)+16,
                             sizeof(TSockAddrIn)+16,
                             FAcceptReceived,
                             POverlapped(@AcceptExBuffer.PerHandleData.m_overlap));

  if( (nRetVal=FALSE) and (WSAGetLastError()<>WSA_IO_PENDING)) then
  begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage(Format('PostAcceptProcess投递Accept I/O操作失败: %d.', [WSAGetLastError()]));
    {$ENDIF}
    Result := FALSE;
    Exit;
  end;

  //性能分析器 增加AcceptEx I/O数量
  {$IFDEF _IOCP_MONITOR}
      _DIMonitor.AddIOCPAcceptEx;
  {$ENDIF}
  Result := TRUE;
end;

function TDIIocpTcpServer.IsSecurityConnection(FDIBuffer: TDIBuffer): Boolean;
var
  LocalAddrLen, RemoteAddrLen: Integer;
  FLocalAddr, FRemoteAddr: PSockAddr;
  sRemoteIPAddr: String;
begin
  {
  //获取客户端IP地址
  m_lpfnGetAcceptExSockaddrs( FDIBuffer.GetBuffer,
                              0,
                              sizeof(TSockAddrIn)+16,
                              sizeof(TSockAddrIn)+16,
                              FLocalAddr,
                              LocalAddrLen,
                              FRemoteAddr,
                              RemoteAddrLen );
  sRemoteIPAddr := FWinSocket.GetRemoteIPAddr(FRemoteAddr^);
  }
  Result := TRUE;
end;

function TDIIocpTcpServer.OnWSAAcceptEx(FDIBuffer: TDIBuffer; dwIoSize: DWORD): Boolean;
begin
  //判断接受到的数据为零,则断开连接。
	if(FDIBuffer.m_Socket = INVALID_SOCKET) then begin

    {$IFDEF _ICOP_DEBUGERR}
        AppendErrorLogMessage('OnWSAAcceptEx m_Socket = INVALID_SOCKET, 关闭客户端Socket连接.');

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -