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

на главную - закладки

Жанры

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

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

Шрифт:

end;

Данный метод вызывается в обработчике нажатия кнопки Остановить и при завершении приложения. Сервер можно многократно останавливать и запуска вновь, не завершая приложение.

Чтобы увидеть все возможности сервера, потребуется новый клиент. На компакт-диске он называется EventSelectClient, но "EventSelect" в данном случае означает только то, что клиент является парным к серверу EventSelectServer. Сам клиент функцию

WSAEventSelect
не использует, поскольку она неудобна, когда нужно работать только с одним сокетом. Поэтому клиент работает в асинхронном режиме, основанном на сообщениях, т.е. посредством функции
WSAAsyncSelect
.

Клиент

может получать от сервера сообщения двух видов: те. которые сервер посылает в ответ на запросы клиента, и те, которые он посылает по собственной инициативе. Но различить эти сообщения клиент не может: например, если клиент отправляет запрос серверу, а потом получает от него сообщение, он не может определить, то ли это сервер ответил на его запрос, то ли именно в этот момент сервер сам отправил клиенту свое сообщение. Соответственно, сообщения обоих типов читает один и тот же код.

Примечание

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

Подключение клиента к серверу выполняется точно так же, как в листинге 2.16, за исключением того, что после выполнения функции

connect
сокет переводится в асинхронный режим, и его события
FD_READ
и
FD_CLOSE
связываются с сообщением
WM_SOCKETMESSAGE
. Обработчик этого сообщения приведен в листинге 2.66.

Листинг 2.66. Получение данных клиентом

procedure TESClientForm.WMSocketMessage(var Msg: TWMSocketMessage);

const

 // Размер буфера для получения данных

 RecvBufSize = 4096;

var

 // Буфер для получения данных

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

 RecvRes: Integer;

 P: Integer;

begin

 // Защита от "тупой" ошибки

 if Msg.Socket <> FSocket then

 begin

MessageDlg('Внутренняя ошибка программы — неверный сокет',

mtError, [mbOK], 0);

Exit;

 end;

 if Msg.SockError <> 0 then

 begin

MessageDlg('Ошибка при взаимодействии с сервером'#13#10 +

GetErrorString(Msg.SockError), mtError, [mbOK], 0);

OnDisconnect;

Exit;

 end;

 case Msg.SockEvent of

 FD_READ:

 // Получено сообщение от сервера

 begin

// Читаем столько, сколько можем

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

if RecvRes > 0 then

begin

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

P := Length(FRecvStr);

SetLength(FRecvStr, P + RecvRes);

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

Move(RecvBuf, FRecvStr[Р + 1], RecvRes);

// В строке может оказаться несколько строк от сервера,

// причем последняя может прийти не целиком.

// Ищем в строке символы #0, которые, согласно протоколу,

// являются разделителями строк.

P := Pos(#0, FRecvStr));

while P > 0 do

begin

AddMessageToRecvMemo('Сообщение от сервера: ' +

Copy(FRecvStr, 1, P - 1));

// Удаляем из строкового буфера выведенную строку

Delete(FRecvStr, 1, P);

P := Pos(#0, FRecvStr);

end;

end

else if RecvRes = 0 then

begin

MessageDlg('Сервер закрыл соединение'#13#10 +

GetErrorString, mtError, [mbOK], 0);

OnDisconnect;

end

else

begin

if WSAGetLastError <> WSAEWOULDBLOCK then

begin

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

GetErrorString, mtError, [mbOK], 0);

OnDisconnect;

end;

end;

 end;

 FD_CLOSE: begin

MessageDlg('Сервер закрыл соединение', mtError, [mbOK], 0);

shutdown(FSocket, SD_BOTH);

OnDisconnect;

 end;

 else begin

MessageDlg('Внутренняя ошибка программы — неизвестное событие ' +

IntToStr(Msg.SockEvent), mtError, [mbOK], 0);

OnDisconnect;

 end;

 end;

end;

Здесь мы используем новый способ чтения данных. Он во многом похож на тот, который применен в сервере. Функция

recv
вызывается один раз за один вызов обработчика значений и передаст данные в буфер фиксированного размера
RecvBuf
. Затем в буфере ищутся границы отдельных строк (символы
#0
), строки, полученные целиком, выводятся. Если строка получена частично (а такое может случиться не только из-за того, что она передана по частям, но и из-за того, что в буфере просто не хватило место для приема ее целиком), её начало следует сохранить в отдельном буфере, чтобы добавить к тому, что будет прочитано при следующем событии
FD_READ
. Этот буфер реализуется полем
FRecvStr
типа
string
. После чтения к содержимому этой строки добавляется содержимое буфера
RecvBuf
, а затем из строки выделяются все подстроки, заканчивающиеся на
#0
. То, что остается в строке
FRecvStr
после этого, — это начало строки, прочитанной частично. Оно будет учтено при обработке следующего события
FD_READ
.

Поделиться:
Популярные книги

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Мастер темных Арканов

Карелин Сергей Витальевич
1. Мастер темных арканов
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Мастер темных Арканов

Измена. Испорченная свадьба

Данич Дина
Любовные романы:
современные любовные романы
короткие любовные романы
5.00
рейтинг книги
Измена. Испорченная свадьба

Блуждающие огни

Панченко Андрей Алексеевич
1. Блуждающие огни
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
Блуждающие огни

Пышка и Герцог

Ордина Ирина
Фантастика:
юмористическое фэнтези
историческое фэнтези
фэнтези
5.00
рейтинг книги
Пышка и Герцог

Затерянные земли или Великий Поход

Михайлов Дем Алексеевич
8. Господство клана Неспящих
Фантастика:
фэнтези
рпг
7.89
рейтинг книги
Затерянные земли или Великий Поход

Адвокат Империи 2

Карелин Сергей Витальевич
2. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 2

Газлайтер. Том 6

Володин Григорий
6. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 6

Часовая битва

Щерба Наталья Васильевна
6. Часодеи
Детские:
детская фантастика
9.38
рейтинг книги
Часовая битва

Невеста снежного демона

Ардова Алиса
Зимний бал в академии
Фантастика:
фэнтези
6.80
рейтинг книги
Невеста снежного демона

Законы Рода. Том 3

Flow Ascold
3. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 3

Случайная свадьба (+ Бонус)

Тоцка Тала
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Случайная свадьба (+ Бонус)

Болотник 2

Панченко Андрей Алексеевич
2. Болотник
Фантастика:
попаданцы
альтернативная история
6.25
рейтинг книги
Болотник 2

Пипец Котенку! 2

Майерс Александр
2. РОС: Пипец Котенку!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Пипец Котенку! 2