Не получается прочитать данные от сервера с помощью SocketRead. ERR_NETSOCKET_IO_ERROR код 5273 - страница 2

 

Посмотрите точное объяснение в комментарии 5.

TLS - это блочный логический режим, который не имеет отношения к физическому количеству сырых байт в сокете. TLS расшифровка работает блоками вплоть до 16-32 кб и поэтому наличия 1292 сырых байт может быть недостаточно для расшифровки блока.

Поэтому алгоритм чтения при TLS должен быть такой:

  • В цикле проверяем наличие любого количества сырых данных, пусть даже 1 байта
  • При наличии в новом цикле вычитываем TLS данные, пока они возвращают хоть байт (именно в цикле)
  • Если не конец, идем дальше ждать
Не путайте и не смешивайте сырое чтение и TLS реализации - будете только ошибаться.
 
Renat Fatkhullin #:

Посмотрите точное объяснение в комментарии 5.

TLS - это блочный логический режим, который не имеет отношения к физическому количеству сырых байт в сокете. TLS расшифровка работает блоками вплоть до 16-32 кб и поэтому наличия 1292 сырых байт может быть недостаточно для расшифровки блока.

Поэтому алгоритм чтения при TLS должен быть такой:

  • В цикле проверяем наличие любого количества сырых данных, пусть даже 1 байта
  • При наличии в новом цикле вычитываем TLS данные, пока они возвращают хоть байт (именно в цикле)
  • Если не конец, идем дальше ждать
Не путайте и не смешивайте сырое чтение и TLS реализации - будете только ошибаться.

Можете привести пример кода, как правильно читать TLS данные?

 
Ivan Titov #:

Можете привести пример кода, как правильно читать TLS данные?

Привел выше псевдокод.

Давайте сами - самое сложное в понимании "сырые байты != расшифрованные".

 
Renat Fatkhullin #:
  • В цикле проверяем наличие любого количества сырых данных, пусть даже 1 байта

Функцией SocketIsReadable?

Renat Fatkhullin #:
  • При наличии в новом цикле вычитываем TLS данные, пока они возвращают хоть байт (именно в цикле)

Функцией SocketTlsReadAvailable? Если да, то с каким значением параметра buffer_maxlen?

Renat Fatkhullin #:
  • Если не конец, идем дальше ждать

Что является признаком конца?

a)функция SocketTlsReadAvailable возвращает -1?

б)возникает ошибка 5273 после вызова SocketTlsReadAvailable?

 
Ivan Titov #:

Функцией SocketIsReadable?

Да.

Функцией SocketTlsReadAvailable? Если да, то с каким значением параметра buffer_maxlen?

Да.

Какой размер - это вам решать, так как это ваш протокол внутри TLS.

Если бинарный типа [type,size, data], то все понятно как и сколько читать. Если же текстовый HTTP/FIX, то выставьте buffer_maxlen например в 16 кб и читайте блоками сколько отдадут.  Гибкость функции SocketTlsReadAvailable как раз в том, что она сразу без ожидания отдаст тот объем, что уже можно декодировать.

А вот SocketTlsRead будет ждать доступности точного количества указанных байт. Что чревато зависанием до таймаута.


Что является признаком конца?

a)функция SocketTlsReadAvailable возвращает -1?

б)возникает ошибка 5273 после вызова SocketTlsReadAvailable?

Возврат -1 означает ошибку с закрытием сокета, если в _LastError находится ошибка 5273 (ERR_NETSOCKET_IO_ERROR).

Документация по MQL5: Предопределенные переменные / _LastError
Документация по MQL5: Предопределенные переменные / _LastError
  • www.mql5.com
_LastError - Предопределенные переменные - Справочник MQL5 - Справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
 

Вообще TLS категорически плохо подходит для шифрации low latency потоковых данных типа ценовых потоков или сделок.

Все из-за того, что:

  1. надо дожидаться полностью сформированного блока для дешифрации
  2. постоянно опрашивать Secure Channel/Crypto API/свою реализацию TLS на предмет "ну вот теперь то с дополнительным куском данных можешь дешифровать блок?"
  3. большой оверхед на мелких пакетах

 
Renat Fatkhullin #:

Какой размер - это вам решать, так как это ваш протокол внутри TLS.

Это WebSocket API криптобиржи (в частности Bybit). Сообщения могут быть любой длины в Jason формате. Признаком конца сообщения является символ "}". Так что длина заранее неизвестна.

Renat Fatkhullin #:

выставьте buffer_maxlen например в 16 кб и читайте блоками сколько отдадут.

Выше писал, что при выставлении значения больше, чем позиция первого символа с нулевым кодом (в данном случае > 1263), возвращает -1 и ошибку 5273. А заранее его позиция в дешифрованном сообщении неизвестна.

Renat Fatkhullin #:

Вообще TLS категорически плохо подходит для шифрации low latency потоковых данных типа ценовых потоков или сделок.

Все криптобиржи для передачи low latency данных используют WebSocket API с базовыми адресами, начинающимися на wss://....
 
Ivan Titov #:


Выше писал, что при выставлении значения больше, чем позиция первого символа с нулевым кодом (в данном случае > 1263), возвращает -1 и ошибку 5273. А заранее его позиция в дешифрованном сообщении неизвестна.

Проверю сегодня сам и отпишусь.

Проверил - у меня все работает с вебсокетами правильно.


Скорее всего у вас ошибка с передачей лишнего нулевого байта в SocketTlsSend, когда обычно строку перекодируют в uchar массив и забывают про конечный 0:

   bool              Send(string request)
     {
      //--- check
      if(m_socket==INVALID_HANDLE)
         return(false);
      //--- convert to array
      char reqbuf[];
      int  reqlen=StringToCharArray(request,reqbuf,0,WHOLE_ARRAY,CP_UTF8);

      if(reqlen<1)
        {
         Close();
         return(false);
        }
      //--- send without last zero
      if(SocketTlsSend(m_socket,reqbuf,reqlen-1)!=reqlen-1)
         return(false);
      //---
      return(true);
     }

Тестовая заготовка приложена.
Файлы:
SocketTLS.mqh  4 kb
 
Ivan Titov #:

a)функция SocketTlsReadAvailable возвращает -1?

б)возникает ошибка 5273 после вызова SocketTlsReadAvailable?

Если код выполняется в конце сессии и сервер закрыл соединение, то на вашей стороне даже при возврате -1 и коде ошибки 5273 в приемный массив записываются остаточные данные (если они пришли и расшифровались).

 
Renat Fatkhullin #:

Скорее всего у вас ошибка с передачей лишнего нулевого байта в SocketTlsSend, когда обычно строку перекодируют в uchar массив и забывают про конечный 0:

Пробовал разные варианты, даже посимвольное заполнение массива в цикле. Результат тот же. Но похоже дело в сервере конкретной биржи, т.к. другие биржи работают нормально.

Stanislav Korotky #:

Если код выполняется в конце сессии и сервер закрыл соединение, то на вашей стороне даже при возврате -1 и коде ошибки 5273 в приемный массив записываются остаточные данные (если они пришли и расшифровались).

Так и есть, но похоже с одной поправкой: если указываешь длину меньше сообщения, то ошибка не возвращается.

Проблема видимо с неправильным запросом для установки соединения:

GET wss://ftx.com/ws/ HTTP/1.1
Host: ftx.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: f94dc353f4676b37b064655ad1c1102c2fa13fb78f73410a7a0e8bd1a5a14f45

Возвращает:

HTTP/1.1 400 Bad Request
Date: Sat, 01 Oct 2022 10:14:02 GMT
Content-Length: 77
Connection: keep-alive
CF-Cache-Status: DYNAMIC
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Server: cloudflare
CF-RAY: 75346dd2ccd8164e-DME
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400

Может кто знает, что не так в запросе?