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

на главную

Жанры

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

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

Шрифт:

begin

EditReply.Text := PChar(@Buf[0]);

Break;

end;

Inc(BufStart, BufStep);

 until False;

end;

Реакция на кнопку Отсоединиться совсем простая: нужно разорвать соединение и закрыть сокет (листинг 2.18).

Листинг 2.18. Реакция на нажатие кнопки Отсоединиться

procedure TSimpleClientForm.BtnDisconnectClick(Sender: TObject);

begin

 shutdown(FSocket, SD_BOTH);

 closesocket(FSocket);

 OnDisconnect;

end;

Откомпилируем

наши примеры и посмотрим, что получилось. Пока у нас один клиент работает с одним сервером, все вполне предсказуемо: клиент передает сообщения, сервер на них отвечает. Попытаемся подключиться вторым клиентом, не отключая первый, и посмотрим, что будет. Само подключение с точки зрения клиента проходит нормально, хотя сервер находится в своем внутреннем цикле и не вызывает
accept
, для второго клиента. Впрочем, как мы знаем, для успешного выполнения функции connect на стороне клиента достаточно, чтобы сокет сервера находился в режиме прослушивания. Теперь попытаемся отправить что-то серверу со второго клиента. Сама отправка проходит успешно, но при попытке получить ответ клиент "зависает", т.к. функция
recv
блокирует нить до прихода данных, а данные не приходят, потому что сервер не обрабатывает сообщения от этого клиента. Отсоединим первый клиент от сервера, чтобы сервер вернулся к выполнению функции
accept
. Мы видим, что сервер немедленно обнаружил подключение второго клиента, а также то, что клиент прислал ему сообщение. Соответственно, сервер отвечает на это сообщение, и второй клиент "отвисает" — теперь с ним можно нормально работать.

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

MultithreadedServer
на компакт-диске). Нам понадобится одна нить для выполнения функции accept и по одной нити на работу с каждым подключившимся клиентом. Инициализация выполняется при нажатии кнопки Запустить (листинг 2.19). После инициализации библиотеки сокетов, создания сокета и перевода его в режим прослушивания она создает нить типа
TListenThread
, передает ей дескриптор сокета и больше с сокетами не работает — дальнейшая роль главной нити заключается только в обработке сообщений. Благодаря этому сервер может иметь нормальный пользовательский интерфейс.

Листинг 2.19. Инициализация многонитевого сервера

// Реакция на кнопку Запустить

procedure TServerForm.BtnStartServerClick(Sender: TObject);

var

 // Сокет, который будет "слушать"

 ServerSocket: TSocket;

 // Адрес, к которому привязывается слушающий сокет

 ServerAddr: TSockAddr;

begin

 // Формирyем адрес для привязки.

 FillChar(ServerAddr.sin_zero, SizeOf(ServerAddr.sin_zero), 0);

 ServerAddr.sin_family := AF_INET;

 ServerAddr.sin_addr.S_addr := ADDR_ANY;

 try

ServerAddr.sin_port := htons(StrToInt(EditPortNumber.Text));

if ServerAddr.sin_port = 0 then

begin

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

mtError, [mbOK], 0);

Exit;

end;

// Создание сокета

ServerSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if ServerSocket = INVALID_SOCKET then

begin

MessageDlg('Ошибка при создании сокета: '#13#10 + GetErrorString,

mtError, [mbOK], 0);

Exit;

end;

// Привязка сокета к адресу

if bind(ServerSocket, ServerAddr, SizeOf(ServerAddr)) = SOCKET_ERROR then

begin

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

GetErrorString, mtError, [mbOK], 0);

closesocket(ServerSocket);

Exit;

end;

// Перевод сокета в режим прослушивания

if listen(ServerSocket, SOMAXCONN) = SOCKET_ERROR then

begin

MessageDlg('Ошибка при переводе сокета в режим просушивания:'#13#10 +

GetErrorString, mtError, [mbOK], 0);

closesocket(ServerSocket);

Exit;

end;

// Запуск нити, обслуживающей слушающий сокет

TListenThread.Create(ServerSocket);

// Перевод элементов управления в состояние "Сервер работает"

LabelPortNumber.Enabled := False;

EditРоrtNumber.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;

Слушающая" нить

TListenThread
состоит из бесконечного ожидания подключения клиента. Каждый раз при подключении клиента библиотека сокетов создаёт новый сокет, и для работы с ним создается новая нить типа
TClientThread
(листинг 2.20).

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

Замуж второй раз, или Ещё посмотрим, кто из нас попал!

Вудворт Франциска
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Замуж второй раз, или Ещё посмотрим, кто из нас попал!

Протокол "Наследник"

Лисина Александра
1. Гибрид
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Протокол Наследник

Сердце Дракона. Том 11

Клеванский Кирилл Сергеевич
11. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
6.50
рейтинг книги
Сердце Дракона. Том 11

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Шесть принцев для мисс Недотроги

Суббота Светлана
3. Мисс Недотрога
Фантастика:
фэнтези
7.92
рейтинг книги
Шесть принцев для мисс Недотроги

Хочу тебя любить

Тодорова Елена
Любовные романы:
современные любовные романы
5.67
рейтинг книги
Хочу тебя любить

Огни Аль-Тура. Желанная

Макушева Магда
3. Эйнар
Любовные романы:
любовно-фантастические романы
эро литература
5.25
рейтинг книги
Огни Аль-Тура. Желанная

Начальник милиции 2

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

Мастер...

Чащин Валерий
1. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
6.50
рейтинг книги
Мастер...

Сумеречный стрелок 8

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

Я до сих пор не князь. Книга XVI

Дрейк Сириус
16. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я до сих пор не князь. Книга XVI

Обыкновенные ведьмы средней полосы

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

Метаморфозы Катрин

Ром Полина
Фантастика:
фэнтези
8.26
рейтинг книги
Метаморфозы Катрин

Идеальный мир для Социопата

Сапфир Олег
1. Социопат
Фантастика:
боевая фантастика
рпг
постапокалипсис
6.17
рейтинг книги
Идеальный мир для Социопата