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

📄 cltcpserver.pas

📁 Clever_Internet_Suite_6.2的代码 Clever_Internet_Suite_6.2的代码 Clever_Internet_Suite_6.2的代码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
  end;
end;

procedure TclTcpServer.ServerError(E: Exception);
begin
  if FIsStart then
  begin
    FStartError := E.Message;
    if (E is EclSocketError) then
    begin
      FStartErrorCode := (E as EclSocketError).ErrorCode;
    end;
  end;
{$IFDEF LOGGER}clPutLogMessage(Self, edInside, 'ServerError', E);{$ENDIF}
  DoServerError(E);
end;

procedure TclTcpServer.VerifyClient(Sender: TObject;
  ACertificate: TclCertificate; const AStatusText: string;
  AStatusCode: Integer; var AVerified: Boolean);
var
  ns: TclNetworkStream;
begin
  ns := (Sender as TclNetworkStream);
  DoVerifyClient((ns.Connection as TclCommandConnection), ACertificate, AStatusText, AStatusCode, AVerified);
end;

procedure TclTcpServer.DoVerifyClient(AConnection: TclCommandConnection;
  ACertificate: TclCertificate; const AStatusText: string;
  AStatusCode: Integer; var AVerified: Boolean);
begin
  if Assigned(OnVerifyClient) then
  begin
    OnVerifyClient(Self, AConnection, ACertificate, AStatusText, AStatusCode, AVerified);
  end;
end;

{ TclTcpServerWorkItem }

constructor TclTcpServerWorkItem.Create(AServer: TclTcpServer;
  AConnection: TclCommandConnection; AOperation: TclTcpServerOperation);
begin
  inherited Create();
  FServer := AServer;
  FConnection := AConnection;
  FConnection._AddRef();
  FOperation := AOperation;
end;

destructor TclTcpServerWorkItem.Destroy;
begin
  FConnection._Release();
  inherited Destroy();
end;

procedure TclTcpServerWorkItem.DoRead;
var
  readStream: TStream;
begin
  readStream := TMemoryStream.Create();
  try
    FConnection.BeginWork();
    try
      if FConnection.FIsReading then Exit;
      FConnection.FIsReading := True;
      FConnection.ReadData(readStream);
    finally
      FConnection.FIsReading := False;
      FConnection.EndWork();
    end;
    FServer.DoReadConnection(FConnection, readStream);
  finally
    readStream.Free();
  end;
end;

procedure TclTcpServerWorkItem.DoWrite;
begin
{$IFDEF LOGGER}try clPutLogMessage(Self, edEnter, 'DoWrite');{$ENDIF}
  FConnection.BeginWork();
  try
    if (FConnection.FWriteStream.Position < FConnection.FWriteStream.Size - 1) then
    begin
      FConnection.WriteData(FConnection.FWriteStream);
    end;
    FServer.DoWriteConnection(FConnection);
  finally
    FConnection.EndWork();
  end;
{$IFDEF LOGGER}clPutLogMessage(Self, edLeave, 'DoWrite'); except on E: Exception do begin clPutLogMessage(Self, edLeave, 'DoWrite', E); raise; end; end;{$ENDIF}
end;          

procedure TclTcpServerWorkItem.Execute;
begin
  Assert(FServer <> nil);
  try
    FConnection.InitProgress(0, 0);
    case FOperation of
      soServerRead: DoRead();
      soServerWrite: DoWrite();
    end;
  except
    on EAbort do ;
    on E: Exception do
    begin
{$IFDEF LOGGER}clPutLogMessage(Self, edInside, 'Execute ServerError', E);{$ENDIF}
      FServer.ServerError(E);
    end;
  end;
end;

function TclTcpServer.GetMaxThreadCount: Integer;
begin
  Result := FWorkerThreadPool.MaxThreadCount;
end;

function TclTcpServer.GetMinThreadCount: Integer;
begin
  Result := FWorkerThreadPool.MinThreadCount;
end;

procedure TclTcpServer.ReadConnection(AConnection: TclCommandConnection);
begin
  if (AConnection = nil) then Exit;
  if not AConnection.FIsReading then
  begin
    FWorkerThreadPool.QueueWorkItem(TclTcpServerWorkItem.Create(Self, AConnection, soServerRead));
  end;
end;

procedure TclTcpServer.WriteConnection(AConnection: TclCommandConnection);
begin
  if (AConnection = nil) then Exit;
  FWorkerThreadPool.QueueWorkItem(TclTcpServerWorkItem.Create(Self, AConnection, soServerWrite));
end;

procedure TclTcpServer.SetMaxThreadCount(const Value: Integer);
begin
  FWorkerThreadPool.MaxThreadCount := Value;
end;

procedure TclTcpServer.SetMinThreadCount(const Value: Integer);
begin
  FWorkerThreadPool.MinThreadCount := Value;
end;

procedure TclTcpServer.Start;
begin
{$IFDEF DEMO}
{$IFNDEF STANDALONEDEMO}
  if FindWindow('TAppBuilder', nil) = 0 then
  begin
    MessageBox(0, 'This demo version can be run under Delphi/C++Builder IDE only. ' +
      'Please visit www.clevercomponents.com to purchase your ' +
      'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    ExitProcess(1);
  end else
{$ENDIF}
  begin
{$IFNDEF IDEDEMO}
    MessageBox(0, 'Please visit www.clevercomponents.com to purchase your ' +
      'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    IsCertDemoDisplayed := True;
    IsEncoderDemoDisplayed := True;
{$ENDIF}
  end;
{$ENDIF}
  if (FServerThread <> nil) then
  begin
    raise EclSocketError.Create(cServerStarted, -1);
  end;

  FIsStart := True;
  try
    FStartError := '';
    FStartErrorCode := 0;

    FServerThread := TclServerThread.Create(Self);
    FServerThread.Start();

    if (FStartError <> '') or (FStartErrorCode <> 0) then
    begin
      InternalStop();

      if (FStartError = '') then
      begin
        FStartError := cStartError;
      end;
      if (FStartErrorCode = 0) then
      begin
        FStartErrorCode := -1;
      end;
      raise EclSocketError.Create(FStartError, FStartErrorCode);
    end;
  finally
    FIsStart := False;
  end;

  DoStart();
end;

procedure TclTcpServer.InternalStop;
begin
  FServerThread.Stop();
  FServerThread.Free();
  FServerThread := nil;
  FWorkerThreadPool.Stop();
end;

procedure TclTcpServer.Stop;
begin
  if (FServerThread = nil) then Exit;
  InternalStop();
  DoStop();
end;

{ TclServerThread }

constructor TclServerThread.Create(AServer: TclTcpServer);
begin
  inherited Create(True);
  FServer := AServer;
end;

procedure TclServerThread.Execute;
var
  dwResult: DWORD;
begin
  try
    FStopEvent := 0;
    FConnections := nil;
    FWindowHandle := 0;
    FServerSocket := INVALID_SOCKET;
    try
      OpenServerSocket();
      SetEvent(FStartedEvent);

      repeat
        dwResult := MsgWaitForMultipleObjects(1, FStopEvent, FALSE, INFINITE, QS_ALLEVENTS or QS_ALLINPUT);
        case dwResult of
          WAIT_OBJECT_0 + 1: DispatchMessages();
        end;
      until dwResult = WAIT_OBJECT_0;

    finally
      CloseServerSocket();
    end;
  except
    on E: Exception do
    begin
      Assert(FServer <> nil);
{$IFDEF LOGGER}clPutLogMessage(Self, edInside, 'Execute ServerError', E);{$ENDIF}
      FServer.ServerError(E);
    end;
  end;
  if (FStartedEvent <> 0) then
  begin
    SetEvent(FStartedEvent);
  end;
end;

procedure TclServerThread.CloseConnection(AConnection: TclCommandConnection);
begin
{$IFDEF LOGGER}try clPutLogMessage(Self, edEnter, 'CloseConnection');{$ENDIF}
  if (AConnection = nil) or (FConnections.IndexOf(AConnection) < 0) then Exit;
  AConnection.BeginWork();
  try
    FConnections.Remove(AConnection);
  finally
    AConnection.EndWork();
  end;
  AConnection.Abort();
  FServer.CloseConnection(AConnection);
{$IFDEF LOGGER}clPutLogMessage(Self, edLeave, 'CloseConnection'); except on E: Exception do begin clPutLogMessage(Self, edLeave, 'CloseConnection', E); raise; end; end;{$ENDIF}
end;

procedure TclServerThread.ReadConnection(AConnection: TclCommandConnection);
begin
  Assert(FServer <> nil);
  FServer.ReadConnection(AConnection);
end;

procedure TclServerThread.AcceptConnection;
var
  connection: TclCommandConnection;
  res: Integer;
begin
  Assert(FServer <> nil);
  connection := FServer.CreateConnection();
  try
    FConnections.Add(connection);
{$IFDEF LOGGER}clPutLogMessage(Self, edInside, 'AcceptConnection');{$ENDIF}
    connection._AddRef();

    if (FServer.UseTLS = stImplicit) then
    begin
      connection.NetworkStream := TclTlsNetworkStream.Create();
      TclTlsNetworkStream(connection.NetworkStream).OnGetCertificate := FServer.GetCertificate;
      TclTlsNetworkStream(connection.NetworkStream).TLSFlags := FServer.TLSFlags;
      TclTlsNetworkStream(connection.NetworkStream).RequireClientCertificate := FServer.RequireClientCertificate;
      TclTlsNetworkStream(connection.NetworkStream).OnVerifyPeer := FServer.VerifyClient;
    end else
    begin
      connection.NetworkStream := TclNetworkStream.Create();
    end;

    connection.Socket := FServerSocket;
    connection.BatchSize := FServer.BatchSize;
    connection.BitsPerSec := FServer.BitsPerSec;
    connection.OnReady := AcceptConnectionDone;

    connection.AcceptConnection();
    
    res := WSAAsyncSelect(connection.Socket, FWindowHandle, CL_SOCKETEVENT, FD_READ + FD_WRITE + FD_CLOSE);
    if (res = SOCKET_ERROR) then
    begin
      RaiseSocketError(WSAGetLastError());
    end;

    connection.AcceptConnectionDone();
  except
    FServer.CloseConnection(connection);
    raise;
  end;
end;

procedure TclServerThread.AcceptConnectionDone(Sender: TObject);
begin
  FServer.DoAcceptConnection(Sender as TclCommandConnection);
  (Sender as TclCommandConnection).OnReady := nil;
end;

procedure TclServerThread.CloseServerSocket;
begin
  if (FServerSocket <> INVALID_SOCKET) then
  begin
    shutdown(FServerSocket, SD_BOTH);
    closesocket(FServerSocket);
  end;
  if (FWindowHandle <> 0) then
  begin
    DeallocateHWnd(FWindowHandle);
  end;
  ClearConnections();
  FConnections.Free();
  if (FStopEvent > 0) then
  begin
    CloseHandle(FStopEvent);
    FStopEvent := 0;
  end;
end;

procedure TclServerThread.OpenServerSocket;
var
  srv_address: TSockAddrIn;
  res: Integer;
begin
  FStopEvent := CreateEvent(nil, False, False, nil);
  if (FStopEvent = 0) then
  begin
    RaiseSocketError(GetLastError());
  end;

  FConnections := TList.Create();
  FWindowHandle := AllocateHWnd(WndProc);
  if (FWindowHandle = 0) then
  begin
    RaiseSocketError(GetLastError());
  end;

  FServerSocket := socket(AF_INET, SOCK_STREAM, 0);
  if (FServerSocket = INVALID_SOCKET) then
  begin
    RaiseSocketError(WSAGetLastError());
  end;

  srv_address.sin_family := AF_INET;
  srv_address.sin_addr.s_addr := INADDR_ANY;

  if (FServer.Port <= 0) then
  begin
    raise EclSocketError.Create(cInvalidPort, -1);
  end;
  srv_address.sin_port := htons(FServer.Port);

  res := bind(FServerSocket, TSockAddr(srv_address), SizeOf(TSockAddrIn));
  if (res = SOCKET_ERROR) then
  begin
    RaiseSocketError(WSAGetLastError());
  end;

  res := WSAAsyncSelect(FServerSocket, FWindowHandle, CL_SOCKETEVENT, FD_ACCEPT);
  if (res = SOCKET_ERROR) then
  begin
    RaiseSocketError(WSAGetLastError());
  end;

  res := listen(FServerSocket, SOMAXCONN);
  if (res = SOCKET_ERROR) then
  begin
    RaiseSocketError(WSAGetLastError());
  end;
end;

function TclServerThread.FindConnection(ASocket: TSocket): TclCommandConnection;
var
  i: Integer;
begin
  for i := 0 to FConnections.Count - 1 do
  begin
    Result := TclCommandConnection(FConnections[i]);
    if (Result.Socket = ASocket) then Exit;
  end;
  Result := nil;
end;

procedure TclServerThread.ClearConnections;
begin
  while FConnections.Count > 0 do
  begin
{$IFDEF LOGGER}clPutLogMessage(Self, edInside, 'ClearConnections, %d', nil, [FConnections.Count]);{$ENDIF}
    TclCommandConnection(FConnections[FConnections.Count - 1])._Release();
    FConnections.Delete(FConnections.Count - 1);
  end;
end;

⌨️ 快捷键说明

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