А. Григорьев - О чём не пишут в книгах по Delphi

Тут можно читать онлайн А. Григорьев - О чём не пишут в книгах по Delphi - бесплатно ознакомительный отрывок. Жанр: comp-programming, издательство БХВ-Петербург, год 2008. Здесь Вы можете читать ознакомительный отрывок из книги онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    О чём не пишут в книгах по Delphi
  • Автор:
  • Жанр:
  • Издательство:
    БХВ-Петербург
  • Год:
    2008
  • Город:
    СПб
  • ISBN:
    978-5-9775-019003
  • Рейтинг:
    4.25/5. Голосов: 81
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание

О чём не пишут в книгах по Delphi - описание и краткое содержание, автор А. Григорьев, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.

Для программистов

О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок

О чём не пишут в книгах по Delphi - читать книгу онлайн бесплатно (ознакомительный отрывок), автор А. Григорьев
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

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

begin

LogMessage('Ошибка в событии FD_WRITE: ' +

GetErrorString(NetEvents.iErrorCode[FD_WRITE_BIT)));

Break;

end;

// Отправляем то, что лежит в буфере

if not DoSendBuf then Break;

end;

if NetEvents.lNetworkEvents and FD_CLOSE <> 0 then

begin

// Клиент закрыл соединение

if NetEvents.iErrorCode[FD_CLOSE_BIT] <> 0 then

begin

LogMessage('Ошибка в событии FD_CLOSE: ' +

GetErrorString(NetEvents.iErrorCode[FD_CLOSE_BIT]));

Break;

end;

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

shutdown(FSocket, SD_BOTH);

Break;

end;

end;

WSA_WAIT_FAILED: begin

LogMessage('Ошибка при ожидании сообщения: ' + GetErrorString);

Break;

end;

else begin

LogMessage(

'Внутренняя ошибка сервера — неверный результат ожидания ' +

IntToStr(WaitRes));

Break;

end;

end;

until False;

closesocket(FSocket);

LogMessage('Нить остановлена');

end;

// Функция возвращает True, если нить завершилась

function TClientThread.GetFinished: Boolean;

begin

// Ждем окончания работы нити с нулевым тайм-аутом.

// Если нить завершена, вернется WAIT_OBJECT_0.

// Если еще работает, вернется WAIT_TIMEOUT.

Result := WaitForSingleObject(Handle, 0) = WAIT_OBJECT_0;

end;

// Метод для остановки нити извне.

// Взводим соответствующее событие, а остальное сделаем

// при обработке события

procedure TClientThread.StopThread;

WSASetEvent(FEvents[0]);

end;

Модуль WinSock2_Events, появившийся в списке uses, содержит объявления констант, типов и функций из WinSock 2, которые понадобятся в программе. Модуль ShutdownConstсодержит объявления констант для функции shutdown, которые отсутствуют в модуле WinSock Delphi 5 и более ранних версиях — этот модуль нам понадобился, чтобы программу можно было откомпилировать в Delphi 5.

Нить использует три события, дескрипторы которых хранятся в массиве FEvents. Событие FEvents[0]служит для уведомления нити о том, что необходимо завершиться, FEvents[1]— для уведомления о том, что нужно оправить данные, FEvents[2]связывается с событиями на сокете. Такой порядок выбран не случайно. Если взведено несколько событий, функция WSAWaitForMultipleEventsвернет результат, соответствующий событию с самым младшим из взведенных событий индексом. Соответственно, чем ближе к началу массива, тем более высокий приоритет у события. Событие, связанное с сокетом, имеет наинизший приоритет для того, чтобы повысить устойчивость сервера к DoS-атакам. Если приоритет этого события был бы выше, чем события остановки нити, то в случае закидывания сервера огромным количеством сообщений от клиента, событие FD_READбыло бы всегда взведено, и сервер все время тратил бы на обработку этого события, игнорируя сигнал об остановке нити. Соответственно, сигнал об остановке должен иметь самый высокий приоритет, чтобы остановке нити ничего не могло помешать. Тем, как отправляются сообщения, сервер управляет сам. поэтому не приходится ожидать проблем, связанных с тратой излишних ресурсов на обработку сигнала отправки. Соответственно, этому событию присваивается приоритет, промежуточный между событием остановки нити и событием сокета.

Так как клиент по новому протоколу перед отправкой сообщения не обязан ждать, пока сервер ответит на предыдущее, возможны ситуации, когда ответ на следующее сообщение сервер должен готовить уже тогда, когда предыдущее еще не отправлено. Кроме того, сервер может отправить сообщение по собственной инициативе, и этот момент тоже может наступить тогда, когда предыдущее сообщение еще не отправлено. Таким образом, мы вынуждены формировать очередь сообщений в том или ином виде. Так как протокол TCP, с одной стороны, может объединять несколько пакетов в один, а с другой, не обязан отправлять отдельную строку за один раз, проще всего не делать очередь из отдельных строк, а заранее объединять их в одном буфере и затем пытаться отправить все содержимое буфера. Таким буфером в нашем случае является поле FSendBuf, метод SendStringдобавляет строку в этот буфер, a DoSendBufотправляет данные из этого буфера. Если все данные отправить за один раз не удалось, отправленные данные удаляются из буфера, а оставшиеся будут отправлены при следующем вызове SendBuf. Все операции с буфером FSendBuf выполняются внутри критической секции, т.к. функция SendStringможет вызываться из других нитей. К каждой строке добавляется символ #0, который, согласно протоколу, является для клиента разделителем строк в потоке.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


А. Григорьев читать все книги автора по порядку

А. Григорьев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




О чём не пишут в книгах по Delphi отзывы


Отзывы читателей о книге О чём не пишут в книгах по Delphi, автор: А. Григорьев. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x