Читаем О чём не пишут в книгах по Delphi полностью

 // соединения клиентом или из-за ошибки в сети.

 repeat

  // Читаем длину присланной клиентом строки и помещаем ее в StrLen

  case ReadFromSocket(FSocket, StrLen, SizeOf(StrLen)) of

  0: begin

   LogMessage('Клиент закрыл соединение');

   Break;

  end;

  -1: begin

   LogMessage('Ошибка при получении данных от клиента: ' +

    GetErrorString);

   Break;

  end;

  end;

  // Протокол не допускает строк нулевой длины

  if StrLen <= 0 then

  begin

   LogMessage('Неверная длина строки от клиента: ' +

    IntToStr(StrLen));

   Break;

  end;

  // Установка длины строки в соответствии с полученным значением

  SetLength(Str, StrLen);

  // Чтение строки нужной длины

  case ReadFromSocket(FSocket, Str[1], StrLen) of

  0: begin

   LogMessage('Клиент закрыл соединение');

   Break;

  end;

  -1: begin

   LogMessage('Ошибка при получении данных от клиента: ' +

    GetErrorString);

   Break;

  end;

  end;

  LogMessage('Получена строка: ' + Str);

  // Преобразование строки

  Str :=

   AnsiUpperCase(StringReplace(Str, #0, '#0', [rfReplaceAll]),

    ' (Multithreaded server)';

  // Отправка строки. Отправляется на один байт больше, чем

  // длина строки, чтобы завершающий символ #0 тоже попал в пакет

  if send(FSocket, Str[1], Length(Str) + 1, 0) < 0 then

  begin

   LogMessage('Ошибка при отправке данных клиенту: ' +

    GetErrorString);

   Break;

  end;

  LogMessage('Клиенту отправлен ответ: ' + Str);

 until False;

 closesocket(FSocket);

end;


procedure TClientThread.LogMessage(const Msg: string);

begin

 FMessage := FHeader + Msg;

 Synchronize(DoLogMessage);

end;

Метод LogMessage здесь несколько видоизменен по сравнению с предыдущими примерами: к каждому сообщению он добавляет адрес клиента, чтобы пользователь мог видеть, с каким именно из одновременно подключившихся клиентов связано сообщение. Что же касается кода Execute, то видно, что он практически не отличается от кода внутреннего цикла простейшего сервера (см. листинг 2.15). Это неудивительно — сообщение здесь читается и обрабатывается единым образом. Вся разница только в том, что теперь у нас одновременно могут работать несколько таких нитей, обеспечивая одновременную работу сервера с несколькими клиентами.

Этот сервер уже можно использовать как образец для подражания. Нужно только помнить, что он тратит на каждого клиента относительно много ресурсов, и поэтому не подходит там, где могут подключаться сотни и более клиентов одновременно. Кроме того, этот сервер очень уязвим по отношению к DoS-атакам, поэтому подобный сервер целесообразен там. где число клиентов относительно невелико, а вероятность DoS-атак низка.

Примечание

DoS-атака (Denied of Service) — способ помешать функционированию сервера, заключающийся в загрузке его бесполезной работой. В простейшем случае — это просто одновременное подключение большого числа клиентов. У нас даже простое подключение большого числа клиентов приводит к большому расходу системных ресурсов, поэтому DoS-атакой можно добиться неработоспособности не только самого сервера, но и системы в целом. Полностью защититься от DoS-атаки невозможно, но можно снизить урон, наносимый ею. Об этом мы поговорим далее.

2.1.13. Определение готовности сокета

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже