Synapse: проверка TCP соединения

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

Ответить
Аватара пользователя
Ichthyander
энтузиаст
Сообщения: 701
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань
Контактная информация:

Synapse: проверка TCP соединения

Сообщение Ichthyander »

Как можно проверять существует ли еще TCP соединение. Библиотека Synapse ararat. Клиентская часть.
1. Клиент устанавливает соединение, делает апгрейд соединение до SSL.
2. Получаем приветствие от TCP сервера.
3. Отправляю команду на логин. Получаю ответ.
Все, можно работать.
Суть в том, что сессия работает в пределах одного логина и одного TCP соединения.
Скорее всего через 5 или 10 минут TCP сервер закрывает сессию и закрывает TCP соединение при бездействии. Чтобы поддерживать соединение можно отправлять команду HELLO на сервер с периодом меньшим, чем время таймаута для сессии.
Но вот вопрос, как проверить на всякий случай перед отправкой: TCP соедение-то еще присутствует или нет? Понятно, можно дождать ответа от сервера с ошибкой, и заново создать соединение и залогинится. Но нет ли какой-либо проверки возможности: могу ли я отправить новую команду серверу в пределах последнего TCP соединения?
P.S. Если кто-то понимает о чем, то я пытаюсь реализовать EPP протокол клиентской части
MysticCoder
постоялец
Сообщения: 154
Зарегистрирован: 14.09.2013 00:20:28

Сообщение MysticCoder »

function RecvBuffer(Buffer: TMemory; Length: Integer): Integer; virtual;

Note: This is low-level receive function. You must be sure if data is waiting for read before call this function for avoid deadlock!

Waits until allocated buffer is filled by received data. Returns number of data received, which equals to LENGTH value under normal operation. If it is not equal the communication channel is possibly broken.

On stream oriented sockets if is received 0 bytes, it mean 'socket is closed!"

On datagram socket is readed first waiting datagram.
Аватара пользователя
Ichthyander
энтузиаст
Сообщения: 701
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань
Контактная информация:

Сообщение Ichthyander »

MysticCoder писал(а):
function RecvBuffer(Buffer: TMemory; Length: Integer): Integer; virtual;

Note: This is low-level receive function. You must be sure if data is waiting for read before call this function for avoid deadlock!

Waits until allocated buffer is filled by received data. Returns number of data received, which equals to LENGTH value under normal operation. If it is not equal the communication channel is possibly broken.

On stream oriented sockets if is received 0 bytes, it mean 'socket is closed!"

On datagram socket is readed first waiting datagram.

Ну в моем конкретном случае, я не ожидаю входящего пакета. Мне нужно просто отправить пакет данных, а уже потом получать пакет данных. По ошибке LastError узнаю, конечно, что соединение разорвано. Но, как и в приведенном Вами случае, узнаем об этом "постфактум" в виде неудавшейся отправке или приема данных. Я думал, может есть какой-то флаг или функция проверки, типа CanRead или CanWrite.
Видимо протокол EPP создан для случаев когда между сервером и клиентом очень стабильное и быстрое соединение, когда разрывы TCP соединения происходят крайне редко. Что собственно и понятно раз его используют для общения между собой серверы регистраторов и в редких случаях разрешается и клиентам регистраторов.
Аватара пользователя
serbod
постоялец
Сообщения: 449
Зарегистрирован: 16.09.2016 10:03:02
Откуда: Минск
Контактная информация:

Сообщение serbod »

Поддержкой TCP занимается ОС, поэтому все вопросы к ней. Есть два основных способа проверки соединения, это:
- регулярно проверять состояние буферов приёма/отправки неблокирующими функциями через ioctl(socket), в synapse это CanRead/CanWrite и чтение размера буферов.
- назначить Callback и пользоваться блокирующими функциями чтения/записи. Но это довольно сложный и рискованный способ, и не особо кроссплатформенный.
olegy123
долгожитель
Сообщения: 1643
Зарегистрирован: 25.02.2016 11:10:20

Сообщение olegy123 »

Ichthyander писал(а):Но вот вопрос, как проверить на всякий случай перед отправкой: TCP соедение-то еще присутствует или нет?

при отправке получишь ошибку это будет означать, что со связью что то случилось..
При чтении данных тоже вывалится ошибка. то же будет означать конец..
Аватара пользователя
Pavia
постоялец
Сообщения: 290
Зарегистрирован: 07.01.2011 11:46:51

Сообщение Pavia »

TCP не имеет такого понятия. Но можно использовать расширение keep-alive.
http://rsdn.org/article/net/keep_alive.xml
MaratIsk
постоялец
Сообщения: 125
Зарегистрирован: 20.08.2009 18:15:20

Сообщение MaratIsk »

Код: Выделить всё

    FSynClient.Connect(FHost, FPort);
    if (FSynClient.LastError <> 0) and (FSynClient.LastError <> 10056) then begin
      try
        FSynClient.CloseSocket;
        FSynClient.Connect(FHost, FPort);
        if (FSynClient.LastError <> 0) then
         raise Exception.Create(IntToStr(FSynClient.LastError) + ' ' + FSynClient.LastErrorDesc);
      except
        raise;
      end;
    end;
Аватара пользователя
Ichthyander
энтузиаст
Сообщения: 701
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань
Контактная информация:

Сообщение Ichthyander »

Ну по поводу keep-alive и подобных пингов, собственно, примерно об этом я и написал начальном посте топика. Можно периодически отправлять команду HELLO серверу и получать ответы (GREETING) для избежания принудительного разрыва TCP соединения со стороны сервера по причине превышения таймаута. Думал есть родные для TCP сокетов проверки соединения.
---- -----
Чтобы не создавать новой смежной темы по поводу TCP решил опубликовать вновь возникший вопрос здесь же.
Вот у меня есть поток, который после отправки команды освобождается. Сокет (TTCPBlockSocket) создается внутри потока и тоже освобождается соответственно. Традиционно в потоках нужные данные между сессиями и отправками команд к серверу я сохранял передавая данные потока основному. Но вот, что делать в данном случае, если мне нужно сохранить TCP соединение, но объект класса TTCPBlockSocket также соответственно уничтожится.
Варианты:
1. Создавать сокет в основном потоке (при это устанавливать соединение в потоке).
2. Как то можно сохранить TCP соединение между двумя объектами сокета (TTCPBlockSocket)? Чтобы при уничтожении объекта сокета (TTCPBlockSocket) TCP соединение не закрывалось, более того, в последующем при создании нового объекта сокета как-то восстановить данные непрерванного TCP-соединения?
3. Все варианты плохи? И каждый раз авторизоваться для отправки команды (по-моему плохой неоптимальнй вариант)

Добавлено спустя 4 минуты 52 секунды:
MaratIsk писал(а):

Код: Выделить всё

    FSynClient.Connect(FHost, FPort);
    if (FSynClient.LastError <> 0) and (FSynClient.LastError <> 10056) then begin
      try
        FSynClient.CloseSocket;
        FSynClient.Connect(FHost, FPort);
        if (FSynClient.LastError <> 0) then
         raise Exception.Create(IntToStr(FSynClient.LastError) + ' ' + FSynClient.LastErrorDesc);
      except
        raise;
      end;
    end;

Тему с проверкой TCP соединения без отправки или приема сообщения решил "закрыть" для себя. Но все же, можете сопроводить комментариями приведенный Вами код? Я не понял назначения этого кода.

Добавлено спустя 36 минут 14 секунд:
Пока думаю просто создавать и хранить сокет в основном потоке. А уже соединятся и обрабатывать в соответствующем для этого потоке [который иногда останавливается и уничтожается]
MaratIsk
постоялец
Сообщения: 125
Зарегистрирован: 20.08.2009 18:15:20

Сообщение MaratIsk »

смысл прост - перед отправкой запроса или данных производится попытка установить подключение. если оно живо - будет LastError = 10056 и код просто пойдет дальше

Добавлено спустя 55 секунд:
а иначе будет произведена попытка нового коннекта
Аватара пользователя
Ichthyander
энтузиаст
Сообщения: 701
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань
Контактная информация:

Сообщение Ichthyander »

MaratIsk писал(а):смысл прост - перед отправкой запроса или данных производится попытка установить подключение. если оно живо - будет LastError = 10056 и код просто пойдет дальше

Добавлено спустя 55 секунд:
а иначе будет произведена попытка нового коннекта

Хм... Интересно, попробую также
MysticCoder
постоялец
Сообщения: 154
Зарегистрирован: 14.09.2013 00:20:28

Сообщение MysticCoder »

Ichthyander писал(а):Вот у меня есть поток, который после отправки команды освобождается. Сокет (TTCPBlockSocket) создается внутри потока и тоже освобождается соответственно. Традиционно в потоках нужные данные между сессиями и отправками команд к серверу я сохранял передавая данные потока основному. Но вот, что делать в данном случае, если мне нужно сохранить TCP соединение, но объект класса TTCPBlockSocket также соответственно уничтожится.

Заведи себе какой нибудь менеджер этих сокетов и храни сокеты там. В простейшем случае хотя бы TList.
Аватара пользователя
Ichthyander
энтузиаст
Сообщения: 701
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань
Контактная информация:

Сообщение Ichthyander »

MysticCoder писал(а):
Ichthyander писал(а):Вот у меня есть поток, который после отправки команды освобождается. Сокет (TTCPBlockSocket) создается внутри потока и тоже освобождается соответственно. Традиционно в потоках нужные данные между сессиями и отправками команд к серверу я сохранял передавая данные потока основному. Но вот, что делать в данном случае, если мне нужно сохранить TCP соединение, но объект класса TTCPBlockSocket также соответственно уничтожится.

Заведи себе какой нибудь менеджер этих сокетов и храни сокеты там. В простейшем случае хотя бы TList.

Более того, мне даже не нужно создавать для этого новый список. Он уже есть по сути. Просто добавил свойство объект.
К моменту этого поста - уже все работает: cохраняю объекты TTCPBlockSocket в основном потоке в массиве объектов для хранения
olegy123
долгожитель
Сообщения: 1643
Зарегистрирован: 25.02.2016 11:10:20

Сообщение olegy123 »

Ichthyander писал(а):Думал есть родные для TCP сокетов проверки соединения.
да никакой магии нет, два хоста пытаются обмениваться сообщением через узлы сами узлы невидимые, пути могут меняться как и фрагментироватся.. там сильно подвязана теория вероятности.
Сделано просто - если от другого хоста пакет не приходит(вроде до 2х дней) TCP соединение будет считаться актуальным.
Keepalive же позволяет прочухать актуальность линка. переодически посылаются ASK пакеты.. если ответа нет после нескольких(все эти параметры корректируются) в течении определенного времени то ось считает, что соединение разорвано. Конечно можно посылать свои HELLO пакеты на уровне приложения..
У меня был опыт работы с GSM связью - там пакеты шли более 2х минут. При таких клиентах нужно это учитывать.

Ichthyander писал(а):3. Все варианты плохи? И каждый раз авторизоваться для отправки команды (по-моему плохой неоптимальнй вариант)
У меня была задача такая: создавался сокет под ним создавался поток который обслуживал данного клиента. Поддерживал протокол. Время жизни сокета равнялось времени жизни потока. По протоколу поток мог завершится и его сокет тоже уничтожался..
Понадобилось обмен сообщениями между клиентами. Пришлось делать список регистрации. Создался поток - к нему прикрепился сокет, поток регистрируется в списке.. Если нужно передать данные - делается поиск по этому списку. Когда поток завершается - он выписывается из списка.

Добавлено спустя 13 минут 11 секунд:
Когда встал вопрос про передачу голоса в рамках одного TCP подключения. Стал рассматривать асинхронное передачу данных в рамках этого протокола. Протокол предусматривал гарантированное передачу данных и не гарантированное.
Ответить