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

Интервал:

Закладка:

Сделать
Листинг 2.54. Обработчик сообщения WM_SOCKETMESSAGE

// Метод GetConnectionBySocket находит в списке FConnections

// запись, соответствующую данному сокету

function TServerForm.GetConnectionBySocket(S: TSocket): PConnection;

var

I: Integer;

begin

for I := 0 to FConnections.Count - 1 do

if PConnection(FConnections[I]).ClientSocket = S then

begin

Result := FConnections[I];

Exit;

end;

Result := nil;

end;

procedure TServerForm.WMSocketMessage(var Msg: TWMSocketMessage);

var

Connection: PConnection;

Res: Integer;

// Вспомогательная процедура, освобождающая ресурсы, связанные

// с клиентом и удаляющая запись подключения из списка

procedure RemoveConnection;

begin

closesocket(Connection.ClientSocket);

FConnections.Remove(Connection);

Dispose(Connection);

end;

begin

// Ищем соединение по сокету

Connection := GetConnectionBySocket(Msg.Socket);

if Connection = nil then

begin

AddMessageToLog(

'Внутренняя ошибка сервера — не найдено соединение для сокета');

Exit;

end;

// Проверяем, были ли ошибки при взаимодействии

if Msg.SockError <> 0 then

begin

AddMessageToLog('Ошибка при взаимодействии с клиентом ' +

Connection.ClientAddr + ': ' + GetErrorString(Msg.SockError));

RemoveConnection;

Exit;

end;

// Анализируем, какое событие произошло

case Msg.SockEvent of

FD_READ: begin

// Проверяем, на каком этапе находится взаимодействие с клиентом.

if Connection.Phase = tpReceiveLength then

begin

// Этап получения от клиента длины строки. При выполнении этого

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

// в поле Connection.MsgSize. Здесь приходится учитывать, что

// теоретически даже такая маленькая (4 байта) посылка может

// быть разбита на несколько пакетов, поэтому за один раз этот

// этап не будет завершен, и второй раз его придется

// продолжать, загружая оставшиеся байты. Connection.Offset -

// количество уже прочитанных на данном этапе байтов -

// одновременно является смещением, начиная с которого

// заполняется буфер.

Res := recv(Connection.ClientSocket,

(PChar((PConnection.MsgSize + Connection.Offset)^, Connection.BytesLeft, 0);

if Res > 0 then

begin

// Если Res > 0, это означает, что получено Res байтов.

// Соответственно, увеличиваем на Res количество прочитанных

// на данном этапе байтов и на такую же величину уменьшаем

// количество оставшихся.

Inc(Connection.Offset, Res);

Dec(Connection.BytesLeft, Res);

// Если количество оставшихся байтов равно нулю, нужно

// переходить к следующему этапу.

if Connection.BytesLeft = 0 then

begin

// Проверяем корректность принятой длины строки

if Connection.MsgSize <= 0 then

begin

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

Connection.ClientAddr + ': ' + IntToStr(Connection.MsgSize));

RemoveConnection;

Exit;

end;

// Следующий этап - это чтение самой строки

Connection.Phase := tpReceiveString;

// Пока на этом этапе не прочитано ни одного байта

Connection.Offset := 0;

// Осталось прочитать Connection.MsgSize байтов

Connection.BytesLeft := Connection.MsgSize;

// Сразу выделяем память под строку

SetLength(Connection.Msg, Connection.MsgSize);

end;

end

elsе if Res = 0 then

begin

AddMessageToLog('Клиент ' + Connection.ClientAddr +

' закрыл соединение');

RemoveConnection;

Exit;

end

else

// Ошибку WSAEWOULDBLOCK игнорируем, т.к. она говорит

// только о том, что входной буфер сокета пуст, но в целом

// все в порядке - такое вполне возможно при ложных

// срабатываниях сообщения

if WSAGetLastError <> WSAEWOULDBLOCK then

begin

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

Connection.ClientAddr + ': ' + GetErrorString);

RemoveConnection;

Exit;

end;

end

else if Connection.Phase = tpReceiveString then

begin

// Следующий этап - чтение строки. Он практически не отличается

// по реализации от этапа чтения длины строки, за исключением

// того, что теперь буфером, куда помещаются полученные от

// клиента данные, служит не Connection.MsgSize,

// a Connection.Msg.

Res :=

recv(Connection.ClientSocket, Connection.Msg(Connection.Offset + 1),

Connection.BytesLeft, 0);

if Res > 0 then

begin

Inc(Connection.Offset, Res);

Dec(Connection.BytesLeft, Res);

// Если количество оставшихся байтов равно нулю, можно

// переходить к следующему этапу.

if Connection.BytesLeft = 0 then

begin

AddMessageToLog('От клиента ' + Connection.ClientAddr +

' получена строка: ' + Connection.Msg);

// Преобразуем строку. В отличие от предыдущих примеров,

// здесь мы явно добавляем к строке #0. Это связано с тем,

// что при отправке, которая тоже может быть выполнена не

// за один раз, мы указываем индекс того символа строки,

// начиная с которого нужно отправлять данные. И (хотя

// теоретически вероятность этого очень мала) может

// возникнуть ситуация, когда за один раз будут отправлены

// все символы строки, кроме завершающего #0, и тогда при

// следующей отправке начинать придется с него. Если мы

// будем использовать тот #0, который добавляется к концу

// строки автоматически, то в этом случае индекс выйдет за

// пределы диапазона. Поэтому мы вручную добавляем ещё один

// #0 к строке, чтобы он стал законной ее частью.

Connection.Msg :=

AnsiUpperCase(StringReplace(Connection.Msg, #0, '#0', [rfReplaceAll])) +

'(AsyncSelect server)'#0;

// Следующий этап - отправка строки клиенту

Connection.Phase := tpSendString;

// Отправлено на этом этапе 0 байт

Connection.Offset := 0;

// Осталось отправить Length(Connection.Msg) байтов.

// Единицу к длине строки, в отличие от предыдущих

// примеров, не добавляем, т.к. там эта единица нужна была

// для того, чтобы учесть добавляемый к строке

// автоматически символ #0. Здесь мы еще один #0 добавили

// к строке явно, поэтому он уже учтен в функции Length.

Connection.BytesLeft := Length(Connection.Msg);

// Ставим в очередь сообщение с событием FW_WRITE.

// Его получение заставит сервер отправить данные

PostMessage(Handle, WM_SOCKETMESSAGE, Msg.Socket, FD_WRITE);

end;

end

else if Res = 0 then

begin

AddMessageToLog('Клиент ' + Connection.ClientAddr +

' закрыл соединение');

RemoveConnection;

Exit;

end

elsе

// Как обычно, "ошибку" WSAEWOULDBLOCK просто игнорируем

if WSAGetLastError <> WSAEWOULDBLOCK then

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

Интервал:

Закладка:

Сделать


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

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




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


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


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

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