Чтение онлайн

ЖАНРЫ

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

Григорьев Антон Борисович

Шрифт:

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

begin

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

Connection.ClientAddr + ': ' + GetErrorString);

RemoveConnection;

Exit;

end;

end

else if Connection.Phase = tpSendString then

// Если сервер находится на этапе отправки данных,

// а событие FD_READ все же произошло, отмечаем это

Connection.SendRead := True;

 end;

 FD_WRITE: begin

if Connection.Phase = tpSendString then

Поделиться с друзьями: