Объект tServerWinSocket
На уровне этого объекта ведется список соединений с клиентскими сокетами, содержащийся в свойстве:
property Connections[Index: Integer]: TCustomWinSocket;
Общее число соединений (и число элементов в свойстве connections) равно значению свойства:
property ActiveConnections: Integer;
Этим списком и счетчиком удобно пользоваться для рассылки всем клиентам какой-нибудь широковещательной информации, например:
for i:=0 to ServerSocket.Socket.ActiveConnections-1 do ServerSocket.Socket.Connections[i].SendText('Hi!') ;
Тип сервера (блокирующий/неблокирующий) задается свойством
type TServerType = (stNonBlocking, StThreadBlocking) ;
property ServerType: TServerType;
Поскольку сервер, который блокируется каждым чтением/записью, представить себе трудно, разработчики фирмы Inprise пошли таким путем. Блокирующий режим заменен режимом stThreadBlocking. В этом случае при установлении каждого нового соединения запускается отдельный программный поток (объект класса TServerClientThread). Он отвечает за связь с отдельным клиентом, и его блокировка не влияет на работу остальных соединений.
Если вы не хотите порождать TServerClientThread, а хотите описать свой класс потока и использовать его для работы с сокетом, вам нужно создать обработчик события:
property OnGetThread: TGetThreadEvent;
type TGetThreadEvent = procedure (Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread) of object;
B отличие от stThreadBlocking, тип stNonBlocking своим поведением ничем не отличается от описанного выше — операции происходят асинхронно, а программист должен лишь описать реакцию на события, возникающие в момент их окончания.
Как известно, создание и уничтожение нового программного потока влечет собой определенные системные накладные расходы. Чтобы избежать этого, в рассматриваемом объекте ведется кэш потоков. По завершении соединения потоки не уничтожаются, а переводятся в состояние ожидания нового соединения.
Свойство:
property ThreadCacheSize: Integer;
задает количество свободных потоков, которые могут находиться в готовности для установления соединения с клиентом. Это количество должно рассчитываться в зависимости от интенсивности и продолжительности контакта с клиентами. Лишние потоки поглощают системные ресурсы, в первую очередь память и процессорное время. Чтобы оптимизировать использование кэш свободных потоков, полезно поинтересоваться значением двух свойств:
property ActiveThreads: Integer;
property IdleThreads: Integer;
показывающих число активных (занятых обслуживанием клиентов) и простаивающих (ожидающих) потоков соответственно.
Старт и завершение потока, работающего с сокетом, обрамлены событиями:
property OnThreadStart: TThreadNotifyEvent;
property OnThreadEnd: TThreadNotifyEvent;
type TThreadNotifyEvent = procedure (Sender: TObject; Thread: TServerClientThread) of object;
Чтобы избежать ситуации тупиков или гонок при работе с сокетами, имеются два метода:
procedure Lock;
procedure Unlock;
Если вами предусмотрен код, который может вызвать проблемы в многозадачной среде, заключите его между вызовами методов Lock и Unlock – в это время остальные потоки, работающие с сокетами, будут блокированы. Методы чтения и записи для блокирующего и неблокирующего режима существенно отличаются. Рассмотрим сначала те, что предназначены для неблокирующего (асинхронного) режима.
Средства для организации чтения представлены группой из трех методов:
-
function ReceiveLength: Integer; - возвращает число байт, которые могут быть приняты в ответ на оповещение клиента о передаче,
-
function ReceiveText: string; - возвращает прочитанную из сокета текстовую строку,
-
function ReceiveBuf(var Buf; Count: Integer): Integer; - возвращает данные, прочитанные из сокета в буфер Buf, в количестве Count байт
Аналогично, методы:
function SendBuffer(Buf; Count: Integer): Integer;
procedure SendTextfConst(const S: string);
function SendStream(AStream: TStream) : Boolean;
посылают клиенту буфер, текстовую строку и поток данных. В дополнение к этому метод:
function SendStreamThenDropfAStream: TStream) : Boolean; посылает клиенту поток данных и завершает соединение.