Вообще говоря, ситуация, когда сервер не отправит данные за один раз, и их отправка растянется на несколько итераций петли сообщений, настолько редка, что при разработке сервера, к которому не предъявляются повышенные требования по надежности, ее можно было бы вообще не учитывать. Соответственно, возможность получения сервером нового уведомления о поступлении данных до того, как на старое сообщение будет дан ответ, возможна только тогда, когда клиент не соблюдает принятый протокол и посылает несколько сообщений подряд, не дожидаясь ответа.
Наш пример призван продемонстрировать наиболее надежный к подобным действиям клиента сервер, поэтому мы его напишем "по всем правилам".
Как обычно, работа сервера начинается с инициализации слушающего сокета, выполняющейся при нажатии кнопки Запустить (листинг 2.50).
Листинг 2.50. Инициализация сервера, основанного на сообщениях
// Перевод элементов управления в состояние "Сервер работает"
LabelPortNumber.Enabled := False;
EditPortNumber.Enabled := False;
BtnStartServer.Enabled := False;
LabelServerState.Caption := 'Сервер работает';
except
on EConvertError do
// Это исключение может возникнуть только в одном месте -
// при вызове StrToInt(EditPortNumber.Text)
MessageDlg('"' + EditPortNumber.Text +
'" не является целый числом', mtError, [mbOK], 0);
on ERangeError do
// Это исключение может возникнуть только в одном месте -
// при присваивании значения номеру порта
MessageDlg('Номер порта должен находиться в диапазоне 1-65535',
mtError, [mbOK], 0);
end;
end;
Этот код мало чем отличается от того, что мы уже видели (сравните, например, с листингами 2.19 и 2.30). Единственное существенное отличие здесь — вызов функции
WSAAsyncSelect
после перевода сокета в режим прослушивания. Этот вызов связывает событие
FD_ACCEPT
с сообщением
WM_ACCEPTMESSAGE
.
Сообщение
WM_ACCEPTMESSAGE
нестандартное, мы должны сами определить его. Использовать это сообщение сервер будет только для определения момента подключения нового клиента, определять момент прихода данных мы будем с помощью другого сообщения —
WM_SOCKETMESSAGE
, которое тоже нужно определить. И, чтобы легче было писать обработчики для этих сообщений, объявим тип
TWMSocketMessage
, "совместимый" с типом
TMessage
(листинг 2.51).
Листинг 2.51. Сообщения, связанные с сокетами, и тип