- TCP_Server создает "серверный" сокет и назначает ему процедуру чтения поступающих данных
constructor THITCP_Server.Create;
begin
inherited;
Sock := TSocket.Create;
...
Sock.OnRead := _OnRes;
...
end;
TCP.pas
function MWnd(window:hwnd; message:dword; wparam:WPARAM; lparam:LPARAM):LRESULT; stdcall;
var i:integer; sc,sc1:TSocket; buf:string; sz,szMax:integer;
begin
...
case lparam and $FFFF of
FD_ACCEPT: begin // Получено новое подключение
sc1 := TSocket.Create(sc); // <= Похоже, "sc" - это "серверный" сокет; см. конструктор ниже
...
end;
...
end;
constructor TSocket.Create(par:TSocket);
type TChAddr = record c1,c2,c3,c4:byte; end;
var ad:TSockAddr; sz:integer;
begin
FParent := par;
...
OnRead := par.OnRead; // Создаваемому сокету назначается родительская процедура чтения
...
end;
- поскольку THITCP_Server._work_doClose закрывало только "серверный" сокет, "клиентские" сокеты по прежнему могли вызывать процедуру чтения, так как они уже знали её адрес, а объект, в котором она находится (THITCP_Server) всё ещё существует. Именно поэтому не работала отправка данных сервером ("серверный" сокет, отправляющий данные, закрыт).
С чего можно сделать такие выводы:
1) Если принять твою последнюю поправку к THITCP_Server._work_doClose, то также нужно поправить описание к точкам
- doClose - отключает всех присоединенных клиентов и запрещает входящие соединения (останавливает сервер)
- doCloseAll - отключает всех присоединенных клиентов, но не останавливает сервер
2) Вижу одну реальную задачу, когда может применяться старый подход: если серверу нужно иметь не больше указанного количества клиентов. Тогда:
- делается счетчик подключений; если количество равно максимальному, прекращается прием новых подключений, но уже подключенные клиенты продолжают обслуживаться;
- делается счетчик отключений; если клиент отключается - сервер опять начинает принимать входящие подключения;
Но в этом случае нужно, чтобы по doClose не уничтожался "серверный" сокет, а выставлялся флаг запрета входящих подключений в процедуре приема (то есть, не обрабатывать FD_ACCEPT, но обрабатывать остальные команды). Всё это требует дополнительных тестов, так что твой вариант, наверное, на данный момент более предпочтительный.