TTCPBlockSocket не реагирует на CloseSocket

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

TTCPBlockSocket не реагирует на CloseSocket

Сообщение and_rivne » 18.09.2018 16:56:46

Использую synapse
Клиент подключается серверу
Код: Выделить всё
sock.Connect('localhost', port);

Сервер видит это и через
Код: Выделить всё
Socket.OnStatus
показывает
Код: Выделить всё
HR_Accept: Log.Lines.Add('Accept '+TTCPBlockSocket(Sender).GetRemoteSinIP);


Но когда клиент говорит
Код: Выделить всё
sock.CloseSocket;
сервер не реагирует на это!
Я ожидаю, что вылетит HR_SocketClose из набора THookSocketReason.

Как мне понять, что сокет отключился?
and_rivne
новенький
 
Сообщения: 20
Зарегистрирован: 09.12.2011 13:40:42

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение MysticCoder » 18.09.2018 18:28:12

кидай больше кода, по этим строчкам ничего сказать нельзя. где код где ожидается реакция сервера?
вообще сервер создает один прослушивающий сокет, и по сокету на каждого подключенного клиента. возможно ты не на том сокете пытаешься ловить событие?
MysticCoder
постоялец
 
Сообщения: 154
Зарегистрирован: 14.09.2013 00:20:28

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение serbod » 18.09.2018 19:01:49

TCP Сервер умеет только Listen() порт на предмет входящих подключений. Когда ты делаешь Accept() входящего подключения, то сервер создает новый клиентский сокет для этого подключения и возвращает Handle на него. И дальше это подключение работает точно так же, как клиентское.

В UDP все иначе, там нет соединений и нет разницы между сервером и клиентом. Один и тот же сокет может и принимать и отправлять пакеты от любых адресов.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение and_rivne » 18.09.2018 20:28:52

На серваку ловлю конекты и создаю каждому отдельный поток.
Код: Выделить всё
Socket.CreateSocket;//создаем новый сокет
  //связываем сокет с локальным адресом
  Socket.Bind(Socket.LocalName,'57778');
  repeat
     if Socket.CanRead(100) then
       begin
         T:=TProxyThread.Create(True,Socket.Accept);

         //определяем обработчик события
         //на Socket.OnStatus навешена процедура procedure ClientServiceStatus(Sender: TObject; Reason: THookSocketReason; const Value: String);  - код ниже.
         
         T.Socket.OnStatus:=Socket.OnStatus;

         //запускаем на выполнение
         T.Start;
       end;
   until Terminated;


Ну и здесь HR_Accept срабатывает при подключении сокета, а HR_SocketClose - не срабатывает при sock.CloseSocket на стороне клиента.

Код: Выделить всё
procedure ClientServiceStatus(Sender: TObject; Reason: THookSocketReason; const Value: String);
begin
  case Reason of
    HR_Accept: memLog.Lines.Add('Accept '+TTCPBlockSocket(Sender).GetRemoteSinIP);
    HR_SocketClose: memLog.Lines.Add('SocketClose '+Value);
  end;
end; 
and_rivne
новенький
 
Сообщения: 20
Зарегистрирован: 09.12.2011 13:40:42

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение MysticCoder » 18.09.2018 21:07:40

Вообще непонятно как ты повесил просто процедуру на этот OnStatus, ведь объявление выглядит как THookSocketStatus = procedure(Sender: TObject; Reason: THookSocketReason; const Value: String) of object;, то есть метод объекта. Ну да ладно.
Почему бы просто не логировать какой именно Reason и Value приходит при отсоединении? В справке написано, что HR_SocketClose срабатывает при CloseSocket и скорее всего только в том случае если этот CloseSocket вызывается на этой стороне соединения. Если в TCP удаленный сокет штатно закрывается, то обычно на локальный сокет приходит сообщение, мол примите данные, но размер данных = 0. Т.е. попробуй ловить HR_ReadCount с value = 0.
MysticCoder
постоялец
 
Сообщения: 154
Зарегистрирован: 14.09.2013 00:20:28

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение and_rivne » 19.09.2018 09:53:40

попробуй ловить HR_ReadCount с value = 0.

К сожалению HR_ReadCount не происходит.
Скорее всего, проблема в том, что я смотрю на статус сокета-сервера.
Какие есть варианты, чтобы понять, что клиент отвалился?
Я могу циклом перебрать клиентов. Но что проверять? CanRead и CanWrite не означают что клиент отвалился.
and_rivne
новенький
 
Сообщения: 20
Зарегистрирован: 09.12.2011 13:40:42

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение serbod » 19.09.2018 10:39:05

Проверяй после каждой операции CanRead() и Read()/Write()
Код: Выделить всё
function TSynSockReader.IsConnected(): Boolean;
begin
  Result := ((Socket.LastError = 0) or (Socket.LastError = WSAETIMEDOUT));
end;


Текстовое описание ошибки в LastErrorDesc
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение and_rivne » 19.09.2018 11:14:58

Проверяй после каждой операции CanRead()

Даже когда клиенты отключились, после CanRead(10)/CanWrite(10), значение Socket.LastError равняется 0 !!
А Socket.SendString('test') дает ошибку.
Но мне нужно проверить не посылая данных.
and_rivne
новенький
 
Сообщения: 20
Зарегистрирован: 09.12.2011 13:40:42

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение serbod » 19.09.2018 13:03:27

Ну, это уже от операционной системы зависит. Я такую фигню видел, когда в системе стоял какой-то сетевой драйвер от Huavei, и там не только TCP сессии не рвались, но и вообще контроль целостности TCP (CRC, порядок пакетов) не работал. Еще что-то подобное бывает в виртуальных сетях VPN.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение and_rivne » 19.09.2018 13:33:44

Тогда еще один вопрос.
Когда я подключаюсь к серваку по
Код: Выделить всё
sock.Connect(edServerIP.Text, edServerPort.Text);

то могу ли я получить какой-то "идентификатор коннекта" от сервера?
and_rivne
новенький
 
Сообщения: 20
Зарегистрирован: 09.12.2011 13:40:42

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение serbod » 19.09.2018 14:04:21

and_rivne писал(а):то могу ли я получить какой-то "идентификатор коннекта" от сервера?

От операционной системы можно получить handle сокета, по сути то же самое, что handle файла. Но передавать этот handle в другие программы нельзя. Вернее, можно, но только копию, сделаную через DuplicateHandle().

Если используется какая-то библиотека или объектно-ориентированная обертка, то с хендлами незачем заморачиваться. Но основы знать полезно в любом случае, там ничего сложного.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение and_rivne » 12.10.2018 15:41:37

По статусу сокетов:
Почему то система умеет видеть состояние моих сокетов
http://joxi.ru/LmGGj98ueLZygm
Вот бы мне такое через TTCPBlockSocket посмотреть?
Думал что в исходниках найду ответ:
Код: Выделить всё
function TBlockSocket.InternalCanRead(Timeout: Integer): Boolean;
var
  TimeVal: PTimeVal;
  TimeV: TTimeVal;
  x: Integer;
  FDSet: TFDSet;
begin
  TimeV.tv_usec := (Timeout mod 1000) * 1000;
  TimeV.tv_sec := Timeout div 1000;
  TimeVal := @TimeV;
  if Timeout = -1 then
    TimeVal := nil;
  FDSet := FFdSet;
  x := synsock.Select(FSocket + 1, @FDSet, nil, nil, TimeVal);
  SockCheck(x); //<------------- Здесь они ловят ошибки
  if FLastError <> 0 then
    x := 0;
  Result := x > 0;
end;


Но для моих сокетов это возвращает одинаковый ответ (Result, то 1 то 4 для всех)
and_rivne
новенький
 
Сообщения: 20
Зарегистрирован: 09.12.2011 13:40:42

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение MysticCoder » 13.10.2018 01:53:21

попробуй getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len); или getpeername
MysticCoder
постоялец
 
Сообщения: 154
Зарегистрирован: 14.09.2013 00:20:28

Re: TTCPBlockSocket не реагирует на CloseSocket

Сообщение olegy123 » 13.10.2018 07:39:34

and_rivne писал(а):Почему то система умеет видеть состояние моих сокетов
вообще то есть уровни OSI
https://ru.wikipedia.org/wiki/%D0%A1%D0 ... %D1%8C_OSI

через
soсket-ы доступны первые (7,6,5) уровни. есть raw-socket-ы которые позволяют формировать пакеты 4.транспортного уровня - интернет был бы другим, Допусти реализацию "клиент недоступен" как то самим пришлось делать..Пакет ушел, время прошло - значит связи не будет...это все нужно кодить.. ОС берет это на себя - программисту хватит создать нужный сокет и положить в него данные.

and_rivne писал(а):Почему то система умеет видеть состояние моих сокетов
система обязана видеть этот уровень, зачем нужно знать состояние чужих сокетов? Сокет после того как был закрыт и приложение завершено, продолжает "жить" какое то время, сигнализируя о том что он закрыт... так нужно.

Есть инструмент/ либла pcap, которая может работать до физики. Там будет все - вплоть до замены пикселей в пакетах.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 34

Рейтинг@Mail.ru