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

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

Жанры

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

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

Шрифт:

'" не является целым числом', mtError, [mbOK], 0);

on ERangeError do

// Это исключение может возникнуть только в одном месте -

// при присваивании значения номеру порта

MessageDlg('Номер порта должен находиться в диапазоне 1-65535',

mtError, [mbOK], 0);

 end;

end;

Так как протокол TCP допускает разбиение посылки на произвольное число пакетов, возможна ситуация,

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

Взаимодействие сервера с клиентом состоит из трех этапов. На первом этапе сервер получает от клиента четырёхбайтное значение — длину строки. На втором этапе сервер получает от клиента саму строку, размер которой уже известен из величины, полученной на первом этапе. На третьем этапе сервер отправляет ответ клиенту, состоящий из строки, завершающейся нулем. Чтобы при очередном "тике" таймера сервер мог продолжить общение с клиентом, прерванное в произвольном месте, необходимо запоминать, на каком этапе было прервано взаимодействие в предыдущий раз, сколько байтов на данном этапе уже прочитано или отправлено и сколько еще осталось прочитать или отправить. Для хранения этих данных мы будем использовать типы

TTransportPhase
и
TConnection
(листинг 2.31).

Листинг 2.31. Типы
TTransportPhase
и
TConnection
 

type

 // Этап взаимодействия с клиентом:

 // tpReceiveLength - сервер ожидает от клиента длину строки

 // tpReceiveString - сервер ожидает от клиента строку

 // tpSendString - сервер посылает клиенту строку

 TTransportPhase = (tpReceiveLength, tpReceiveString, tpSendString);

 // Информация о соединении с клиентом:

 // СlientSocket - сокет, созданный для взаимодействия с клиентом

 // ClientAddr - строковое представление адреса клиента

 // MsgSize - длина строки, получаемая от клиента

 // Msg - строка, получаемая от клиента или отправляемая ему,

 // Phase - этап взаимодействия с данным клиентом

 // Offset - количество байтов, уже полученных от клиента

 // или отправленных ему на данном этапе

 // BytesLeft - сколько байтов осталось получить от клиента

 // или отправить ему на данном этапе

 PConnection = ^TConnection;

 TConnection = record

ClientSocket: TSocket;

ClientAddr: string;

MsgSize: Integer;

Msg: string;

Phase: TTransportPhase;

Offset: Integer;

BytesLeft: Integer;

 end;

Для

каждого подключившегося клиента создается отдельный экземпляр записи
TConnection
, в котором хранится информация как о самом подключении, так и о том, на каком этапе находится взаимодействие с данным клиентом.

Проверка подключения клиентов и взаимодействие с подключившимися ранее реализуется, как уже было сказано, при обработке события таймера. Код обработчика приведен в листинге 2.32. 

Листинг 2.32. Обработчик события таймера

// Обработка сообщения от таймера

// В ходе обработки проверяется наличие вновь подключившихся клиентов

// а также осуществляется обмен данными с клиентами

procedure TServerForm.TimerReadTimer(Sender: TObject);

var

 // Сокет, который создается для вновь подключившегося клиента

 ClientSocket: TSocket;

 // Адрес подключившегося клиента

 ClientAddr: TSockAddr;

 // Длина адреса

 AddrLen: Integer;

 // Вспомогательная переменная для создания нового подключения

 NewConnection: PConnection;

 I: Integer;

begin

 AddrLen := SizeOf(TSockAddr);

 // Проверяем наличие подключении. Так как сокет неблокирующий,

 // accept не будет блокировать нить даже в случае отсутствия

 // подключений.

 ClientSocket := accept(FServerSocket, @ClientAddr, @AddrLen);

 if ClientSocket = INVALID_SOCKET then

 begin

// Если произошедшая ошибка - WSAEWOULDBLOCK, это просто означает,

// что на данный момент подключений нет, а вообще все в порядке,

// поэтому ошибку WSAEWOULDBLOCK мы просто игнорируем. Прочие же

// ошибки могут произойти только в случае серьезных проблем,

// которые требуют остановки сервера.

if WSAGetLastError <> WSAEWOULDBLOCK then

begin

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

GetErrorString + #13#10'Сервер будет остановлен', mtError, [mbOK], 0);

ClearConnections;

closesocket(FServerSocket);

OnStopServer;

end;

 end

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

Неудержимый. Книга VIII

Боярский Андрей
8. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
6.00
рейтинг книги
Неудержимый. Книга VIII

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

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

Восход. Солнцев. Книга I

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

Попаданка

Ахминеева Нина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка

Возлюби болезнь свою

Синельников Валерий Владимирович
Научно-образовательная:
психология
7.71
рейтинг книги
Возлюби болезнь свою

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

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

Ротмистр Гордеев 2

Дашко Дмитрий
2. Ротмистр Гордеев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ротмистр Гордеев 2

Идеальный мир для Лекаря 5

Сапфир Олег
5. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 5

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

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

Жребий некроманта 3

Решетов Евгений Валерьевич
3. Жребий некроманта
Фантастика:
боевая фантастика
5.56
рейтинг книги
Жребий некроманта 3

Город драконов

Звездная Елена
1. Город драконов
Фантастика:
фэнтези
6.80
рейтинг книги
Город драконов

Убивать, чтобы жить

Бор Жорж
1. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать, чтобы жить

Инквизитор Тьмы 2

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

Беглец

Бубела Олег Николаевич
1. Совсем не герой
Фантастика:
фэнтези
попаданцы
8.94
рейтинг книги
Беглец