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

📄 udiiocpsocketserver.pas

📁 楠楠写的DBiocp例子都是源码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
	  Result := False;
    Exit;
  end;
  //WaitThread事件列表m_hPostAcceptEvent
	m_hWaitEventList[1] := m_hPostAcceptEvent;

  //WSAEventSelectI/O模型处理Accept事件
  m_hListenThreadEvent := WSACreateEvent;
  if (m_hListenThreadEvent = WSA_INVALID_EVENT) then begin
    AppendDisplayMsg(Format('WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
    WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit
  end;
  //WaitThread事件列表m_hListenThreadEvent
  m_hWaitEventList[2] := m_hListenThreadEvent;

	//注册FD_ACCEPT事件。
	//如果投递的AcceptEx I/O不够,线程会接收到FD_ACCEPT网络事件,说明应该投递更多的AcceptEx I/O
  nRet := WSAEventSelect(m_sListenSocket, m_hListenThreadEvent, FD_ACCEPT);
  if (nRet = SOCKET_ERROR) then begin
    AppendErrorMessage(Format('WSAAsyncSelect()调用失败: %d.', [WSAGetLastError()]));
		WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit;
  end;

  //加载扩展函数AcceptEx
  if ( WSAIoctl( m_sListenSocket,
                    SIO_GET_EXTENSION_FUNCTION_POINTER,
                    @GuidAcceptEx,
                    sizeof(GuidAcceptEx),
                    @@m_lpfnAcceptEx,
                    sizeof(@m_lpfnAcceptEx),
                    @dwBytesReceived,
                    nil,
                    nil) = SOCKET_ERROR ) then begin
    AppendErrorMessage(Format('WSAIoctl 加载AcceptEx函数失败: %d.', [WSAGetLastError()]));
		WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit;
  end;


  //加载扩展函数GetAcceptExSockaddrs
  if ( WSAIoctl( m_sListenSocket,
                    SIO_GET_EXTENSION_FUNCTION_POINTER,
                    @GuidGetAcceptExSockaddrs,
                    sizeof(GuidGetAcceptExSockaddrs),
                    @@m_lpfnGetAcceptExSockaddrs,
                    sizeof(@m_lpfnGetAcceptExSockaddrs),
                    @dwBytesReceived,
                    nil,
                    nil) = SOCKET_ERROR ) then begin
    AppendErrorMessage(Format('WSAIoctl 加载GetAcceptExSockaddrs函数失败: %d.', [WSAGetLastError()]));
		WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit;
  end;

  FillChar(sock_Addr, SizeOf(sock_Addr), 0);
  sock_Addr.sin_family := AF_INET;
  sock_Addr.sin_addr.S_addr := INADDR_ANY;
  sock_Addr.sin_port := htons(m_nListenPort);
  //绑定套接字
  nRet := Bind(m_sListenSocket, @sock_Addr, sizeof(sock_Addr));
	if (nRet = SOCKET_ERROR) then begin
		AppendErrorMessage(Format('bind() 调用失败: %d.', [WSAGetLastError()]));
    WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit;
	end;
  //侦听
  nRet := Listen(m_sListenSocket, 5);
	if (nRet = SOCKET_ERROR) then begin
		AppendErrorMessage(Format('listen() 调用失败: %d.', [WSAGetLastError()]));
    WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit;
	end;

  //将监听套节字关联到完成端口,注意,这里为它传递的CompletionKey为0
	AssociateSocketWithCompletionPort(m_sListenSocket, m_hCompletionPort, DWORD(0));
  //设置状态,允许客户端连接
  m_bAcceptConnections := TRUE;

  //创建侦听线程,并挂起

  FDIListenThread := TDIListenThread.Create(self);
  if (FDIListenThread = nil) then begin
    AppendErrorMessage(Format('创建ListnerThreadProc线程错误: %d.', [WSAGetLastError()]));
    WSACloseEvent(m_hListenThreadEvent);
    Winsock2.closesocket(m_sListenSocket);
    Result := FALSE;
    Exit;
  end;
  FDIListenThread.Run;

	Result := TRUE;
end;

function TDIIocpSocketServer.PostWSACloseSocket(pClientChannel: TDIClientChannel;  pDIBuffer: TDIBuffer): Boolean;
begin
  if pClientChannel = nil then begin
    AppendErrorMessage('PostWSACloseSocket投递CloseSocket I/O操作失败, pClientChannel is NULL.');
    Result := False;
    Exit;
  end;

  if pDIBuffer = nil then begin
    AppendErrorMessage('PostWSACloseSocket投递CloseSocket I/O操作失败, pDIBuffer is NULL.');
    Result := False;
    Exit;
  end;

  try
    pClientChannel.FContextLock.Lock;
    pDIBuffer.SetOperation(IOWSACloseSocket);
    pDIBuffer.SetupRead;

    if (PostQueuedCompletionStatus( m_hCompletionPort,
                                   0,
                                   DWORD(Pointer(pClientChannel)),
                                   @pDIBuffer.PerHandleData.m_overlap) = False) then
    begin
      AppendErrorMessage(Format('PostWSACloseSocket失败: %d.',[WSAGetLastError()]));
      pClientChannel.FContextLock.UnLock;
      Result := FALSE;
      Exit;
    end;

  finally
    pClientChannel.FContextLock.UnLock;
  end;
  
  Result := TRUE;
end;


procedure TDIIocpSocketServer.ProcessIOMessage(pClientChannel: TDIClientChannel; pDIBuffer: TDIBuffer; dwIoSize: DWORD);
begin
  case pDIBuffer.GetOperation of
	  IOWSAAcceptEx:
      begin
        OnWSAAcceptEx(pDIBuffer);
      end;
	  IOWSARecv:
      begin
        //OnWSARecv(pClientChannel, pDIBuffer, dwIoSize);
      end;
	  IOWSASend:
      begin
        //OnWSASend(pClientChannel, pDIBuffer, dwIoSize);
      end;
  end;
end;

procedure TDIIocpSocketServer.IOWorkerThreadProc;
var
  bIORet: Boolean;
  dwIOSize: DWORD;
  dwIOError: DWORD;
  pBuffer: TDIBuffer;
  pClientChannel: TDIClientChannel;
  pHandleData: PPerHandleData;
begin
  //m_hShutdownEvent事件,线程退出。
  while (WaitForSingleObject(m_hShutdownEvent, INFINITE) <> WAIT_OBJECT_0) do begin
    pHandleData := nil;
    pClientChannel := nil;
    pBuffer := nil;
    dwIOSize := 0;

    bIORet := GetQueuedCompletionStatus( m_hCompletionPort,
                                         dwIOSize,
                                         DWORD(pClientChannel),
                                         POVERLAPPED(pHandleData),
                                         INFINITE );
    //PostQueuedCompletionStatus检查状态-1,以便退出线程
    if (dwIOSize = $FFFFFFFF) then Exit;

    if (pHandleData<> nil) then pBuffer := TDIBuffer(pHandleData.pDIBuffer);
    //计数减一
    if (pClientChannel<>nil) then pClientChannel.ExitIOLoop(pBuffer);

    if (bIORet) then
    begin
      //一.得到正常断开的通知
      //GetQueuedCompletionStatus返回true,并且dwIOSize返回0 且 FClientChannel, pHandleData不为空
      if ( (dwIOSize=0) and (pBuffer<>Nil) and (pClientChannel<>nil) ) then begin
        //触发关闭Socket套接字事件
        //pIOCPServer->OnCloseSocketEvent(lpClientContext, pOverlapBuff);
        //pIOCPServer->DisconnectClient(lpClientContext);
        //pIOCPServer->ReleaseClientContextToPool(lpClientContext);
        //if (pBuffer<> nil) then pIOCPServer.m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
        continue;
      end;

      //二.收到用户自定义退出消息
      if (pBuffer<>Nil) and
         (pBuffer.GetOperation = IOWSACloseSocket) and
         (pClientChannel<>nil) then begin
        //触发关闭Socket套接字事件
        //pIOCPServer->OnCloseSocketEvent(lpClientContext, pOverlapBuff);
        //pIOCPServer->DisconnectClient(lpClientContext);
        //pIOCPServer->ReleaseClientContextToPool(lpClientContext);
        //if (pBuffer<> nil) then pIOCPServer.m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
        continue;
      end;

      //消息分发
      //if (FBuffer<>Nil) pIOCPServer.ProcessIOMessage(FClientChannel, FBuffer, dwIOSize);
    end
    else
    begin
      //三.异常断开(未得到正常断开的通知)
      //GetQueuedCompletionStatus   返回false
      //GetLastError返回ERROR_NETNAME_DELETED或者ERROR_INVALID_PARAMETER

      if (not bIORet) then begin
        dwIOError := GetLastError();
        if ( dwIOError<>WAIT_TIMEOUT ) then begin
          if (pClientChannel<>nil) then begin
            //释放上下文
            if (dwIOError = ERROR_NETNAME_DELETED) or (dwIOError = ERROR_INVALID_PARAMETER) then
            begin
              //触发关闭Socket套接字事件
              //pIOCPServer->OnCloseSocketEvent(lpClientContext, pOverlapBuff);
              //pIOCPServer->DisconnectClient(lpClientContext);
              //pIOCPServer->ReleaseClientContextToPool(lpClientContext);
              //if (pBuffer<> nil) then pIOCPServer.m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
            end;
            continue;
          end;

          if (pBuffer<> nil) then m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
          continue;
        end;

      end;

    end;

  end;
end;


function TDIIocpSocketServer.SetupIOWorkers: Boolean;
var
  i: Integer;
  dwThreadID: DWORD;
  hThread: THandle;
  WorkerThread: TDIWorkerThread;
begin
  SetLength(m_WrokThreads, m_nMaxIOCPIOWorkers);
  for i := 1 to m_nMaxIOCPIOWorkers do begin
    WorkerThread := TDIWorkerThread.Create(self);
    m_WrokThreads[i].nThread := i+1;
    m_WrokThreads[i].FSocketServer := self;
    m_WrokThreads[i].FDIThread := WorkerThread;
    m_WrokThreads[i].hEvent := WorkerThread.Handle;
    WorkerThread.Run;
  end;

  Result := TRUE;
end;

function TDIIocpSocketServer.Startup: Boolean;
var
  bRet: LongBool;
begin
  if (m_bServerStarted) then begin
    Result := False;
    Exit;
  end;

  AppendDisplayMsg(Format('IOCP服务器端启动, 系统版本号: %s.', [IOCP_SERVER_VERSION]));
	//停止服务内核对象
  m_hShutdownEvent := CreateEvent(nil, TRUE, FALSE, nil);
  if (m_hShutdownEvent = WSA_INVALID_EVENT) then begin
    AppendDisplayMsg(Format('WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
    WSACloseEvent(m_hShutdownEvent);
	  Result := False;
    Exit;
  end;

  AppendDisplayMsg(Format('服务器允许客户端最大的连接数: %d.', [FMaxNumConnections]));
  bRet := CreateCompletionPort;
  if (bRet) then
    AppendDisplayMsg('创建完成端口成功.')
  else
  begin
    AppendDisplayMsg('创建完成端口失败.');
    Result := FALSE;
    Exit;
  end;

  //侦听端口
  if ( m_nListenPort>0 ) then begin
    //服务器端启动侦听线程
    bRet := SetupListner();
    if(bRet) then
      AppendDisplayMsg('服务器端启动侦听线程.')
    else
    begin
      AppendErrorMessage('系统异常错误,服务器端侦听线程启动失败.');
      Result := FALSE;
      Exit;
    end;
  end;

  bRet := SetupIOWorkers();
  if(bRet) then
      AppendDisplayMsg('服务器端工作线程启动.')
  else
  begin
    AppendErrorMessage('系统异常错误,服务器端工作线程启动失败.');
    Result := FALSE;
    Exit;
  end;

  if (bRet) then begin
    m_bServerStarted := TRUE;
    AppendDisplayMsg(Format('IOCP服务器端侦听地址: %s, 端口号:%d.', [GetHostIPAddr(), m_nListenPort]));
    AppendDisplayMsg('IOCP服务器端启动成功.');
  end;

  Result := TRUE;
end;

procedure TDIIocpSocketServer.ShutDown;
begin

end;



{
procedure TDITcpSocketServer.DisconnectClient(FClientChannel: TDIClientChannel);

⌨️ 快捷键说明

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