Experts: MQL5 Programming for Traders – 책의 소스 코드. 파트 7 - 페이지 3

 
웹소켓 클래스의 몇 가지 버그 수정 및 개선 사항을 첨부합니다.
파일:
wss.zip  16 kb
 
Stanislav Korotky #:
웹소켓 클래스의 몇 가지 버그 수정 및 개선 사항을 첨부합니다.
여러분의 노력에 감사드립니다.
 
Stanislav Korotky #:
경제 캘린더 읽기 및 CSV로 내보내기와 관련된 버그 수정 및 개선 사항이 코드베이스에 게시되었습니다. 특히, 대부분 정렬된 큰 배열(일반적으로 MQL5 캘린더 API에서 수신)의 경우 정렬 알고리즘이 수정되어 속도 저하와 스택 오버플로가 제거되었습니다.

msclient.mqh 126번 줄의 'return connection.handshake(url, host, origin, custom_headers);'에 '경로' 대신 전체 'url'을 전달하면 파이썬 웹소켓에서 403 오류가 발생하는 문제가 있습니다. 이 변경을 해야만 EA가 제 파이썬 웹소켓 서버에 성공적으로 연결할 수 있었습니다.
변경하기 전에 Postman (통과)과 EA의 서버 로그를 첨부했습니다 (실패)

그러나 다음 문제는 내 서버가 구성된 간격으로 자동 연결 유지 핑을 보내지 만 MT5 웹 소켓 구현이 응답하지 않는 것 같고이 동작으로 인해 서버가 핑 시간 초과 직후에 항상 클라이언트 연결을 끊습니다.

킵얼라이브 핑퐁에 대한 도움을 주시면 감사하겠습니다.

파일:
passed.png  88 kb
failed.png  50 kb
 
pauldic #:

msclient.mqh 126줄의 'return connection.handshake(url, host, origin, custom_headers);'에 '경로' 대신 전체 'url'을 전달하면 파이썬 웹소켓에서 오류 403이 발생합니다. 이 변경을 해야만 EA가 제 파이썬 웹소켓 서버에 성공적으로 연결할 수 있었습니다.
변경하기 전에 Postman (통과)과 EA의 서버 로그를 첨부했습니다 (실패)

그러나 다음 문제는 내 서버가 구성된 간격으로 자동 연결 유지 핑을 보내지 만 MT5 웹 소켓 구현이 응답하지 않는 것 같고이 동작으로 인해 서버가 핑 시간 초과 직후에 항상 클라이언트 연결을 끊습니다.

킵얼라이브 핑퐁에 대한 도움을 주시면 감사하겠습니다.

안녕하세요, 예, 클라이언트 호출에서 경로를 사용할 수 있습니다:

template<typename T>
class WebSocketClient: public IWebSocketObserver
{
   ...
   bool open(const string custom_headers = NULL)
   {
      ...
      connection = new T(&this, socket, compression);
      return connection.handshake(path, host, origin, custom_headers);
   }

반면에 HTTP 요청 구문은 전체 URI를 대상으로 지원하며 원본 소스 코드를 다른 서버 ( wss://ws.postman-echo.com/raw 포함)에 대해 테스트 한 결과 정상적으로 작동했습니다. 그래서 이것이 위반인지 아니면 파이썬의 구현이 어떤 의미에서 너무 경직되어 있는지 잘 모르겠습니다.

핑/퐁에 관해서는 작동할 것입니다. wsprotocol.mqh를 살펴보세요 :

   // 들어오는 제어 프레임 처리: 닫기 요청 후 Pong on Ping을 보내고 연결을 닫습니다.
   void processControlFrame(IWebSocketFrame *frame)
   {
      switch(frame.getType())
      {
      case WS_FRAME_OPCODE::WS_CLOSE_FRAME:
         if(closeRequested) // 마감이 확인되었습니다.
         {
            Print("Server close ack");
         }
         else if(!disconnecting) // 서버가 닫힘 시작
         {
            if(openMessage) // 아직 확정되지 않음(!)
            {
               owner.onMessage(openMessage);
               openMessage = NULL;
            }
          
            WebSocketFrame temp(WS_FRAME_OPCODE::WS_CLOSE_FRAME); // ack 보내기
            sendFrame(&temp);
         }
         close();
         break;
      case WS_FRAME_OPCODE::WS_PING_FRAME:
         {
            IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData());
            sendFrame(temp);
            delete temp;
         }
         break;
      }
   }

서버가 클라이언트에 핑을 보내고 있으니 이 부분을 디버그해 보세요.

 
덧붙여서, ws/sources에 사용되는 MQL5Book/StringUtils.mqh의 새 버전을 추가하는 것을 깜빡했습니다.
파일:
 
Stanislav Korotky #:
덧붙여서, ws/sources에 사용되는 MQL5Book/StringUtils.mqh의 새 버전을 추가하는 것을 깜빡했습니다.
Stanislav Korotky 님의 도움에 다시 한 번 감사드립니다. 파이썬 웹소켓 서버의 핑퐁 문제와 관련하여 추가 디버깅을 통해 서버가 핑 요청을 텍스트 또는 바이너리 데이터로 전송하고 MT5는 텍스트 기반 핑이 전송될 때만 성공적으로 응답하는 것을 발견했습니다. 이를 통해 문제를 추적하고 해결하는 데 도움이 되었습니다.

문제는 웹소켓 프레임이 생성될 때 ws ping 프레임 스위치/케이스 내의 310줄에 있습니다:

IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData());

frame.getData() 서버는 핑 데이터가 텍스트/ 문자열 기반인 경우에만 핑을 인식하는 것 같지만 바이너리 핑이 전송된 경우

따라서 두 경우 모두에서 작동하려면 오버로드된 frame.getData(uchar &buf[])를 사용해야 합니다. (내 변경 사항이) 깨질 다른 사용 사례를 만날지 모르겠지만 지금까지는 모두 괜찮은 것 같습니다.


uchar data[]
; frame.getData(data)
; IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, data);

그냥 호기심에서, 이벤트 핸들러 함수 OnMessage 수신 메시지처럼 보이는데 왜 OnTimer() 이벤트 핸들러를 사용하여 간격으로 메시지를 수동으로 확인해야하는지 궁금합니다. 현재 설정은 그대로 작동하지만이 접근 방식이 왜 필요한지 더 많이 알려 주시면 감사하겠습니다.
 
pauldic #:
스타니슬라브 코로트키 님 도와주셔서 다시 한 번 감사드립니다. 파이썬 웹소켓 서버의 핑퐁 문제와 관련하여 추가 디버깅을 통해 서버가 핑 요청을 텍스트 또는 바이너리 데이터로 전송하고 MT5는 텍스트 기반 핑이 전송될 때만 성공적으로 응답하는 것을 발견했습니다. 이를 통해 문제를 추적하고 해결하는 데 도움이 되었습니다.

문제는 웹소켓 프레임이 생성될 때 ws ping 프레임 스위치/케이스 내의 310줄에 있습니다:

IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData());

frame.getData() 서버는 핑 데이터가 텍스트/ 문자열 기반인 경우에만 핑을 인식하는 것 같지만 바이너리 핑이 전송된 경우

따라서 두 경우 모두에서 작동하려면 오버로드된 frame.getData(uchar &buf[])를 사용해야 합니다. (내 변경 사항이) 깨질 다른 사용 사례를 만날지 모르겠지만 지금까지는 모두 괜찮은 것 같습니다.


uchar data[]
; frame.getData(data)
; IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, data);

그냥 호기심에서, 이벤트 핸들러 함수 OnMessage 수신 메시지처럼 보이는데 왜 OnTimer() 이벤트 핸들러를 사용하여 간격으로 메시지를 수동으로 확인해야하는지 궁금합니다. 현재 설정은 그대로 작동하지만이 접근 방식이 왜 필요한지 더 많이 알려 주시면 감사하겠습니다
.

노력해 주셔서 감사합니다. 소스 코드에 편집 내용을 포함시키는 것을 고려해 보겠습니다.

온타이머와 온메시지는 애플리케이션에서 다른 처리 로직을 구현하고 싶을 수 있기 때문에 제공되는 것입니다. 소켓에서의 읽기는 지정된 시간 초과와 함께 MQL5 API 수준에서 차단됩니다. 따라서 새 메시지 대기, 처리 및 응답 자동 생성에만 관심이 있는 경우 차단 모드(읽기에서 무한 시간 초과 및 OnTimer 없음)에서 수행하면 됩니다. 즉, 앱이 데이터를 대기하는 동안 일종의 정지 상태입니다. 그러나 사용자에게 반응형 UI를 제공해야 하는 경우(채팅 앱의 경우) OnTimer 핸들러에서 짧은 읽기 시도에 대해 작은 시간 제한을 설정하고(시간 초과 시 빈 데이터를 생성할 수 있음) 그 사이에 사용자 작업을 모니터링합니다.

 
Stanislav Korotky #:

노력해 주셔서 감사합니다. 소스 코드에 편집 내용을 포함하도록 하겠습니다.

온타이머와 온메시지의 경우 애플리케이션에서 다른 처리 로직을 구현하고 싶을 수 있기 때문에 제공되는 것입니다. 소켓에서의 읽기는 지정된 시간 초과와 함께 MQL5 API 수준에서 차단됩니다. 따라서 새 메시지 대기, 처리 및 응답 자동 생성에만 관심이 있는 경우 차단 모드(읽기에서 무한 시간 초과 및 OnTimer 없음)에서 수행하면 됩니다. 즉, 앱이 데이터를 대기하는 동안 일종의 정지 상태입니다. 그러나 사용자에게 반응형 UI를 제공해야 하는 경우(채팅 앱의 경우) OnTimer 핸들러에서 짧은 읽기 시도에 대해 작은 시간 제한을 설정하고(시간 초과 시 빈 데이터를 생성할 수 있음) 그 사이에 사용자 작업을 모니터링합니다.

설명해 주신 @StanislavKorotky에게 다시 한 번 감사드립니다.
 

다음은 zip 아카이브에 포함된 wss 소스 코드의 또 다른 사소한 버그 수정 및 개선 사항입니다.

무엇보다도 이제 실패한 업그레이드(예: 권한 부여가 필요하고 101 이외의 상태 코드가 반환되는 경우)를 분석하고 조치를 취할 수 있습니다:

if(wss.open(initial_headers))
{
   // 성공, 정상 흐름
}
else
{
  // 문제가 발생했습니다 - 업그레이드되지 않았거나 연결되지 않았습니다.
  if(wss.isConnected())
  {
     Print("Can't upgrade to websockets");
     bool resolved = false;
     string headers[][2]; // response
     if(wss.getHeaders(headers))
     {
       // TODO: 상태 분석 및 해결
       resolved = ... // true/false
     }
     if(!resolved)
     {
       wss.close(); // 닫아 업그레이드되지 않은 소켓에서 더 이상의 읽기/쓰기 시도를 방지합니다.
     }
     else
     {
       wss.open(updated_headers); // try again
     }
  }
}

또한 StringUtils.mqhURL.mqh도 중요한 수정 사항을 받았습니다.

파일:
wss.zip  16 kb
URL.mqh  5 kb
 

안녕하세요 @Stanislav Korotky, 저는 MQL5를 처음 사용하게 되었습니다. 웹소켓 사용을 위해 wss.zip 파일을 게시한 것을 발견했습니다. 사용 방법, 데모 또는 배울 수있는 것이 있습니까? 진심으로 감사드립니다!

Stanislav Korotky
Stanislav Korotky
  • 2025.04.07
  • www.mql5.com
Trader's profile