На этом шаге мы рассмотрим принципы работы с событиями сокетов.
События, возникающие при работе с сокетами, можно условно разделить на следующие группы:
Когда клиентский сокет открывает соединение, при этом происходит целая цепь событий.
Серверный сокет выполняет сразу две задачи: он поддерживает слушающее соединение и соединения с клиентскими сокетами.
Как только слушающий сокет получает запрос от клиента на соединение, происходит событие OnListen. Здесь, с помощью свойства Socket, вы можете получить сведения относительно клиентского сокета и как-то вмешаться в процесс: например, если вы контролируете процесс подключения клиентов, то здесь вы можете отказать в соединении "нежелательным" IP-адресам.
При установлении соединения с клиентом процесс проходит следующие фазы.
Обмен данными - это очевидно основная задача установленного соединения сокетов. Эта задача может выполняться двумя способами, в зависимости от того, какой тип сокетов мы используем: блокирующие или не блопирующие. Если сокет не блокирующий (у клиентского сокета свойство ClientType имеет значение ctNonBlocking, а у серверного сокета свойству ServerType присвоено значение stNonBlocking), то операции чтения/записи происходят асинхронно и не блокируют выполнение программного кода. Если сокеты используют режим блокировки (у клиентского сокета свойство ClientType имеет значение ctBlocking, а у серверного сокета свойству ServerType присвоено значение stThreadBlocking), операции чтения и записи начинаются только после инициализации. В таком режиме работы при создании нового соединения серверный сокет выделяет для него свой поток, чтобы процесс блокировки не мешал работе остальных соединений. В зависимости от выполняемой задачи бывает, что приходится выделять для процессов чтения и записи на клиентской стороне соединения отдельный поток. Но это уже вам решать - делать это или нет.
В случае неблокирующих сокетов, когда сокет получает запрос на чтение или запись, вызываются события OnRead и OnWrite у клиентского сокета и события OnClientRead и OnClientWrite у серверного сокета. В обработчиках этих событий вы должны разместить соответствующий код, выполняющий эти задачи. Для чтения данных нужно применять методы ReceiveBuf и ReceiveText. Для первого метода сначала нужно узнать размер присылаемого другим сокетом буфера. Сделать это можно при помощи метода ReceiveLength. Чтобы записать данные в соединение сокетов можно использовать один из трех методов: SendBuf, SendStream или SendText. Если применить метод SendStreamThenDrop, то после отправки данных сервер разорвет соединение.
Когда сокеты работают в режиме блокировки, то задача программиста - отслеживать, когда сокет на другом конце соединения готов принять или отправить данные, поскольку блокирующие сокеты не обмениваются такой информацией друг с другом. Программист должен использовать для этой цели свойства и методы объекта TWinSocketStream.
На следующем шаге мы рассмотрим пример использования изученного материала.