Π§ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° Bookidrom.ru! БСсплатныС ΠΊΠ½ΠΈΠ³ΠΈ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΊΠ»ΠΈΠΊΠ΅

Π§ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ½Π»Π°ΠΉΠ½ «О Ρ‡Ρ‘ΠΌ Π½Π΅ ΠΏΠΈΡˆΡƒΡ‚ Π² ΠΊΠ½ΠΈΠ³Π°Ρ… ΠΏΠΎ DelphiΒ». Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° 81

Автор А. Π“Ρ€ΠΈΠ³ΠΎΡ€ΡŒΠ΅Π²

constructor TClientThread.Create(ClientSocket: TSocket; const ClientAddr: TSockAddr);

begin

 FSocket := ClientSocket;

 // Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ содСрТит адрСс ΠΈ Π½ΠΎΠΌΠ΅Ρ€ ΠΏΠΎΡ€Ρ‚Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°.

 // Π­Ρ‚ΠΎΡ‚ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒΡΡ ΠΊΠΎ всСм сообщСниям Π² Π»ΠΎΠ³

 // ΠΎΡ‚ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°.

 FHeader :=

  'Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° ' + inet_ntoa(ClientAddr.sin_addr) +

  ': ' + IntToStr(ntohs(ClientAddr.sin_port)) + ': ';

 // Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ события ΠΈ привязываСм ΠΏΠ΅Ρ€Π²ΠΎΠ΅ ΠΈΠ· Π½ΠΈΡ… ΠΊ сокСту

 FEvents[0] := WSACreateEvent;

 if FEvents[0] = WSA_INVALID_EVENT then

  raise ESocketError.Create(

   FHeader + 'Ошибка ΠΏΡ€ΠΈ создании события: ' + GetErrorString);

 FEvents[1] := WSACreateEvent;

 if FEvents[1] = WSA_INVALID_EVENT then

  raise ESocketError.Create(

   FHeader + 'Ошибка ΠΏΡ€ΠΈ создании события: ' + GetErrorString);

 FEvents[2] := WSACreateEvent;

 if FEvents[2] = WSA_INVALID_EVENT then raise

  ESocketError.Create(

   FHeader + 'Ошибка ΠΏΡ€ΠΈ создании ΡΠΎΠ±Ρ‹Ρ‚ия: ' + GetErrorString);

 if WSAEventSelect(FSocket, FEvents[2], FD_READ or FD_WRITE or FD_CLOSE) =

  SOCKET_ERROR then

  raise ESocketError.Create(

   FHeader + 'Ошибка ΠΏΡ€ΠΈ привязывании сокСта ΠΊ ΡΠΎΠ±Ρ‹Ρ‚ΠΈΡŽ: ' + GetErrorString);

 FSendBufSection := TCriticalSection.Create;

 // ΠžΠ±ΡŠΠ΅ΠΊΡ‚ этой Π½ΠΈΡ‚ΠΈ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒΡΡ сам

 FreeOnTerminate := False;

 inherited Create(False);

end;


destructor TClientThread.Destroy;

begin

 FSendBufSection.Free;

 WSACloseEvent(FEvents[0]);

 WSACloseEvent(FEvents[1]);

 WSACloseEvent(FEvents[2]);

 inherited;

end;


// Ѐункция добавляСт строку Π² Π±ΡƒΡ„Π΅Ρ€ для ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ

procedure TClientThread.SendString(const S: string);

begin

 FSendBufSection.Enter;

 try

  FSendBuf := FSendBuf + S + #0;

 finally

  FSendBufSection.Leave;

 end;

 LogMessage('Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ "' + S + '" поставлСно Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ для ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ');

 // Π’Π·Π²ΠΎΠ΄ΠΈΠΌ событиС, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅

 WSASetEvent(FEvents[1]);

end;


// ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° всСх Π΄Π°Π½Π½Ρ‹Ρ…, Π½Π°ΠΊΠΎΠΏΠ»Π΅Π½Π½Ρ‹Ρ… Π² Π±ΡƒΡ„Π΅Ρ€Π΅

// Ѐункция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ False, Ссли ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка,

// ΠΈ True, Ссли всС Π² порядкС

function TClientThread.DoSendBuf: Boolean;

var

 SendRes: Integer;

begin

 FSendBufSection.Enter;

 try

  // Если ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π½Π΅Ρ‡Π΅Π³ΠΎ, Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ

  if FSendBuf = '' then

  begin

   Result := True;

   Exit;

  end;

  // ΠŸΡ‹Ρ‚Π°Π΅ΠΌΡΡ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ всС, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π² Π±ΡƒΡ„Π΅Ρ€Π΅

  SendRes := send(FSocket, FSendBuf[1], Length(FSendBuf), 0);

  if SendRes > 0 then

  begin

   // УдаляСм ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° Ρ‚Ρƒ Ρ‡Π°ΡΡ‚ΡŒ, которая ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»Π°ΡΡŒ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρƒ

   Delete(FSendBuf, 1, SendRes);

   Result := True;

  end

  else

  begin

   Result := WSAGetLastError = WSAEWOULDBLOCK;

   if not Result then

    LogMessage('Ошибка ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ Π΄Π°Π½Π½Ρ‹Ρ…: ' + GetErrorString);

  end;

 finally

  FSendBufSection.Leave;

 end;

end;


procedure TClientThread.Execute;

const

 // Ρ€Π°Π·ΠΌΠ΅Ρ€ Π±ΡƒΡ„Π΅Ρ€Π° для ΠΏΡ€ΠΈΠ΅ΠΌΠ° сообщСнии

 RecvBufSize = 4096;

var

 // Π‘ΡƒΡ„Π΅Ρ€ для ΠΏΡ€ΠΈΠ΅ΠΌΠ° сообщСний

 RecvBuf: array[0..RecvBufSize - 1] of Byte;

 RecvRes: Integer;

 NetEvents: TWSANetworkEvents;

 // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½Π½Π°Ρ строка

 Str: string;

 // Π”Π»ΠΈΠ½Π° ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΉ строки

 StrLen: Integer;

 // Если ReadLength = True, ΠΈΠ΄Π΅Ρ‚ Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ Π΄Π»ΠΈΠ½Ρ‹ строки,

 // Ссли False - самой строки

 ReadLength: Boolean;

 // Π‘ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚ Π½Π°Ρ‡Π°Π»Π° ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΈΠΊΠ°

 Offset: Integer;

 // Число Π±Π°ΠΉΡ‚ΠΎΠ², ΠΎΡΡ‚Π°Π²ΡˆΠΈΡ…ΡΡ ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ Π΄Π»ΠΈΠ½Ρ‹ строки ΠΈΠ»ΠΈ самой строки

 BytesLeft: Integer;

 Π : Integer;

 I: Integer;

 LoopExit: Boolean;

 WaitRes: Cardinal;

begin

 LogMessage('Π‘ΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ установлСно');

 ReadLength := True;

 Offset := 0;

 BytesLeft := SizeOf(Integer);

 repeat

  WaitRes := WSAWaitForMultipleEvents(3, @FEvents, False, WSA_INFINITE, False);

  case WaitRes of

  WSA_WAIT_EVENT_0: begin

   // Π—Π°ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ соСдинСниС с ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠΌ ΠΈ останавливаСм Π½ΠΈΡ‚ΡŒ

   LogMessage('ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ сигнал ΠΎΠ± остановкС Π½ΠΈΡ‚ΠΈ');

   shutdown(FSocket, SD_BOTH);

   Break;

  end;

  WSA_WAIT_EVENT_0 + 1:

  begin

   // БбрасываСм событиС ΠΈ отправляСм Π΄Π°Π½Π½Ρ‹Π΅

   WSAResetEvent(FEvents[1]);

   if not DoSendBuf then Break;

  end;

  WSA_WAIT_EVENT_0 + 2: begin

   // ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»ΠΎ событиС, связанноС с сокСтом.

   // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ, ΠΊΠ°ΠΊΠΎΠ΅ ΠΈΠΌΠ΅Π½Π½ΠΎ, ΠΈ Π·Π°ΠΎΠ΄Π½ΠΎ сбрасываСм Π΅Π³ΠΎ

   if WSAEnumNetworkEvents(FSocket, FEvents[2], NetEvents) = SOCKET_ERROR then

   begin

    LogMessage('Ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ списка событий: ' + GetErrorString);

    Break;

   end;

   if NetEvents.lNetworkEvents and FD_READ <> 0 then

   begin

    if NetEvents.iErrorCode[FD_READ_BIT] <> 0 then

    begin

     LogMessage('Ошибка Π² событии FD_READ: ' +

      GetErrorString(NetEvents.iErrorCode[FD_READ_BIT]));

     Break;

    end;

    // Π’ Π±ΡƒΡ„Π΅Ρ€Π΅ сокСта Π΅ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅.

    // ΠšΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° сокСта Π² свой Π±ΡƒΡ„Π΅Ρ€ RecvBuf

    RecvRes := recv(FSocket, RecvBuf, SizeOf(RecvBuf), 0);

    if RecvRes > 0 then

    begin

     P := 0;

     // Π­Ρ‚Π° пСрСмСнная Π½ΡƒΠΆΠ½Π° ΠΏΠΎΡ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ здСсь появляСтся

     // Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ», ΠΏΡ€ΠΈ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠΈ ошибки Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π½ΡƒΠΆΠ½ΠΎ

     // Π²Ρ‹ΠΉΡ‚ΠΈ ΠΈ ΠΈΠ· внСшнСго Ρ†ΠΈΠΊΠ»Π° Ρ‚ΠΎΠΆΠ΅. Π’Π°ΠΊ ΠΊΠ°ΠΊ Π² Delphi Π½Π΅Ρ‚

     // конструкции Ρ‚ΠΈΠΏΠ° Break(2) Π² АдС, приходится ΠΏΡ€ΠΈΠ±Π΅Π³Π°Ρ‚ΡŒ

     // ΠΊ Ρ‚Π°ΠΊΠΈΠΌ способам: Ссли Π½ΡƒΠΆΠ΅Π½ Π²Ρ‹Ρ…ΠΎΠ΄ ΠΈΠ· внСшнСго Ρ†ΠΈΠΊΠ»Π°,

     // Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΌ Ρ†ΠΈΠΊΠ»Π΅ выполняСтся LoopExit := True,

     // Π° послС выполнСния Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ Ρ†ΠΈΠΊΠ»Π° провСряСтся

     // Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ этой ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ ΠΈ ΠΏΡ€ΠΈ нСобходимости выполняСтся

     // Π²Ρ‹Ρ…ΠΎΠ΄ ΠΈ ΠΈΠ· Π³Π»Π°Π²Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°.

     LoopExit := False;

     // Π’ этом Ρ†ΠΈΠΊΠ»Π΅ ΠΌΡ‹ ΠΈΠ·Π²Π»Π΅ΠΊΠ°Π΅ΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π°

     // ΠΈ раскидываСм ΠΈΡ… ΠΏΠΎ ΠΏΡ€ΠΈΡ‘ΠΌΠ½ΠΈΠΊΠ°ΠΌ - Str ΠΈ StrLen.

     while Π  < RecvRes do

     begin

      // ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ, сколько Π±Π°ΠΉΡ‚ΠΎΠ² Π½Π°ΠΌ Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ Π±Ρ‹ ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ

      L := BytesLeft;

      // Если Π² Π±ΡƒΡ„Π΅Ρ€Π΅ Π½Π΅Ρ‚ Ρ‚Π°ΠΊΠΎΠ³ΠΎ количСства,

      // Π΄ΠΎΠ²ΠΎΠ»ΡŒΡΡ‚Π²ΡƒΠ΅ΠΌΡΡ Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ

      if Π  + L > RecvRes then L := RecvRes - P;

      // ΠšΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΈΠΊ

      if ReadLength then

Move(RecvBuf[P], (PChar(@StrLen) + Offset)^, L)

      else Move(RecvBuf[P], Str(Offset + 1), L);

      Dec(BytesLeft, L);

      // Если ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π»ΠΈ всС, Ρ‡Ρ‚ΠΎ Ρ…ΠΎΡ‚Π΅Π»ΠΈ,

      // ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ ΠΊ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌΡƒ

      if BytesLeft = 0 then

      begin

       ReadLength := not ReadLength;

       Offset := 0;

       // Если Π·Π°ΠΊΠΎΠ½Ρ‡Π΅Π½ΠΎ Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ строки, Π½ΡƒΠΆΠ½ΠΎ вывСсти Π΅Π΅

       if ReadLength then

       begin

        LogMessage('ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½Π° строка: ' + Str);

        BytesLeft := SizeOf(Integer);

        // Π€ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅ΠΌ ΠΎΡ‚Π²Π΅Ρ‚ ΠΈ записываСм Π΅Π³ΠΎ Π² Π±ΡƒΡ„Π΅Ρ€

        Str :=

         AnsiUpperCase(StringReplace(Str, #0, '#0',

          [rfReplaceAll])) + '(AsyncEvent server)';

        SendString(Str);

        Str := '';

       end

       else

       begin

        if StrLen <= 0 then

        begin

         LogMessage('НСвСрная Π΄Π»ΠΈΠ½Π° строки ΠΎΡ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°: ' +

          IntToStr(StrLen));

         LoopExit := True;

         Break;

        end;

        BytesLeft := StrLen;

        SetLength(Str, StrLen);

       end;

      end

      else Inc(Offset, L);

      Inc(P, L);

     end;

     // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ, Π±Ρ‹Π» Π»ΠΈ Π°Π²Π°Ρ€ΠΈΠΉΠ½Ρ‹ΠΉ Π²Ρ‹Ρ…ΠΎΠ΄ ΠΈΠ· Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ Ρ†ΠΈΠΊΠ»Π°,

     // ΠΈ Ссли Π±Ρ‹Π», Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ ΠΈ ΠΈΠ· внСшнСго, Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ Ρ€Π°Π±ΠΎΡ‚Ρƒ

     // с ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠΌ

     if LoopExit then Break;

    end

    else if RecvRes = 0 then

    begin

     LogMessage('ΠšΠ»ΠΈΠ΅Π½Ρ‚ Π·Π°ΠΊΡ€Ρ‹Π» соСдинСниС ');

     Break;

    end

    else

    begin

     if WSAGetLastError <> WSAEWOULDBLOCK then

     begin

      LogMessage('Ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΡ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°: ' +

       GetErrorString);

     end;

    end;

   end;

   // Π‘ΠΎΠΊΠ΅Ρ‚ Π³ΠΎΡ‚ΠΎΠ² ΠΊ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ Π΄Π°Π½Π½Ρ‹Ρ…

   if NetEvents.lNetworkEvents and FD_WRITE <> 0 then

   begin

    if NetEvents.iErrorCode[FD_WRITE_BIT] <> 0 then