Вверх ↑
Этот топик читают: Гость
Разработчик
Ответов: 26113
Рейтинг: 2126
#121: 2013-01-16 19:51:46 ЛС | профиль | цитата
Netspirit писал(а):
И ещё, что делает точка doClose в TCP_Server? По идее, её вызов должен отключать указанного клиента, но в примере она ничего не делает - клиент может дальше слать данные, а сервер их принимать.

С какго перепуга doClose должно закрывать сервер и отсоединять всех клиентов. А указанного клиента отключать надо как сделано в последней версии пакета Windows на SVN.
карма: 22

0
Ответов: 4628
Рейтинг: 749
#122: 2013-01-16 19:59:11 ЛС | профиль | цитата
nesco писал(а):
doClose должно закрывать сервер и отсоединять всех клиентов

Наверное, для этого служит точка doCloseAll.
карма: 26

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#123: 2013-01-16 20:07:27 ЛС | профиль | цитата
Netspirit писал(а):
Наверное, для этого служит точка doCloseAll.

Но эта точка не уничтожает экземпляр сервера, а только отсоединяет всех клиентов
------------ Дoбавленo в 20.07:
Если залезть в дебри, то видно, что отсоединяются все клиенты при уничтожении экземпляра класса по doClose

destructor TSocket.Destroy;
begin
Close;
if FList<>nil then DisconnectClients;
if FParent<>nil then FParent.FList.Remove(Self);
AllSockets.Remove(Self);
if AllSockets.Count=0 then DestroyWindow;
end;

procedure TSocket.DisconnectClients;
var i:smallint;
begin
for i := FList.Count-1 downto 0 do with Connections[i] do
begin
Close;
Destroy;
end;
FList.Clear;
end;


onCloseAll делает только отсоединение

procedure THITCP_Server._work_doCloseAll;
begin
Sock.DisconnectClients;
end;


карма: 22

0
Ответов: 4628
Рейтинг: 749
#124: 2013-01-16 20:07:52 ЛС | профиль | цитата
Тогда почему
nesco писал(а):
doClose должно закрывать сервер и отсоединять всех клиентов

если это делает doCloseAll?
nesco писал(а):
Но эта точка не уничтожает экземпляр сервера, а только отсоединяет всех клиентов

Возвращаемся к вопросу "что должна делать точка doClose?".
- возьми ExampleInternetTcpTest
- нажми "open" у сервера и у клиента
- нажми "send" у сервера и у клиента - всё работает
- теперь нажми "close" у сервера. После этого "send" у сервера не работает, но "send" у клиента работает.
карма: 26

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#125: 2013-01-16 20:12:00 ЛС | профиль | цитата
Netspirit писал(а):
Возвращаемся к вопросу "что должна делать точка doClose?".

Я же написал, что она должна делать -- уничтожить экземпляр класса с отсоединением всех клиентов
------------ Дoбавленo в 20.12:
Netspirit писал(а):
если это делает doCloseAll?

Ты это чего, эта точка не уничтожает экземпляр сервера, а только отсоединяет клиентов. Млин, но посмотри коды выше
карма: 22

0
Ответов: 4628
Рейтинг: 749
#126: 2013-01-16 20:12:06 ЛС | профиль | цитата
Netspirit писал(а):
- теперь нажми "close" у сервера. После этого "send" у сервера не работает, но "send" у клиента работает

Значит, что-то не уничтожает.
карма: 26

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#127: 2013-01-16 20:13:33 ЛС | профиль | цитата
Netspirit писал(а):
Значит, что-то не уничтожает.

Пример мне дай, который не работает, я на него посмотрю
карма: 22

0
Ответов: 4628
Рейтинг: 749
#128: 2013-01-16 20:14:41 ЛС | профиль | цитата
Netspirit писал(а):
ExampleInternetTcpTest

карма: 26

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#129: 2013-01-16 20:20:11 ЛС | профиль | цитата
Странно, действительно не уничтожается, а ведь должен, событие отключения выдает правильно. А Х его З, копать надо код
карма: 22

0
Ответов: 4628
Рейтинг: 749
#130: 2013-01-16 20:24:19 ЛС | профиль | цитата
Да нет, нужно описание к точкам поправить:
doOpen - запускает сервер и разрешает входящие подключения
doClose - запрещает входящие соединения (но не отключает уже подключенных клиентов)

[offtop]А вообще их нужно было бы обозвать типа doStart/doStop, но это уже невозможно[/offtop]

Или пока ничего не менять, но иметь в виду такое поведение.
карма: 26

0
Ответов: 258
Рейтинг: -27
#131: 2013-01-16 20:43:39 ЛС | профиль | цитата
а фаервол можно сделать с помощью TCP SERVER ?

ну например на сервере запретить внешний доступ к порту, а через TCP server пропускать весь трафик(в обе стороны). Или такое не получится сделать?
карма: 0

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#132: 2013-01-17 00:03:20 ЛС | профиль | цитата
Netspirit писал(а):
но не отключает уже подключенных клиентов

Ты это серверу расскажи, он-то передать клиенту ничего не может, только принимает. Одностороннее соединение какое-то
------------ Дoбавленo в 23.47:
Netspirit, ИМХО. Вот так правильно должно быть, но код построен так, что больше экземпляр не создашь. Изначально неправильно реализован алгоритм работы.

procedure THITCP_Server._work_doClose;
begin
// Sock.Close;
Sock.Destroy;
end;


Смотри, как это реализовано в TCP_ServerEx

procedure THITCP_ServerEx.Close;
var i:integer;
begin
if Assigned(FSock) then begin
for i:=0 to FSock.Count-1 do
FSock.Connections[i].Close;
FSock.Destroy;
FSock := nil;
end;
end;

------------ Дoбавленo в 00.03:
Я так подумал, но чтобы ничего не переделывать и оба сервера работали похожим образом, то можно сделать вот так

procedure THITCP_Server._work_doClose;
begin
Sock.DisconnectClients;
Sock.Close;
end;

карма: 22

0
Ответов: 4628
Рейтинг: 749
#133: 2013-01-17 12:39:48 ЛС | профиль | цитата
Как я понимаю причину глюка:
- 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, но обрабатывать остальные команды). Всё это требует дополнительных тестов, так что твой вариант, наверное, на данный момент более предпочтительный.

карма: 26

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#134: 2013-01-17 12:46:21 ЛС | профиль | цитата
Netspirit писал(а):
делается счетчик подключений

Так он вроде есть

   if Sock.Connected then Sock.Listen(10);
карма: 22

0
Ответов: 4628
Рейтинг: 749
#135: 2013-01-17 12:50:32 ЛС | профиль | цитата
Это не совсем то. Имелось в виду, что счетчики создаются на уровне схемы по событиях сервера onConnect/onDisconnect. На уровне кода сервера делается только запрет/разрешение входящих подключений в процедуре MWnd(...).
карма: 26

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)