SocketTlsReadAvailable

安全なTLS接続からすべてのデータを読み込みます。

int  SocketTlsReadAvailable(
  int           socket,             // ソケット
  uchar&       buffer[],             // ソケットからデータを読むためのバッファ
  const uint   buffer_maxlen         // 読まれるバイト数
  );

パラメータ

socket

[in] SocketCreate関数で返されるソケットハンドルです。 _LastErrorに無効なハンドルが渡されると、5270 (ERR_NETSOCKET_INVALIDHANDLE)がアクティブになります。

buffer

[out] データが読まれるuchar型配列への参照。動的配列サイズは、読み取られたバイト数だけ増えます。配列サイズはINT_MAX (2147483647)を超えることはできません。

buffer_maxlen

[in] buffer[]配列に読まれるバイト数。配列に収まらないデータはソケットに残り、次のSocketTlsReadAvailableまたはSocketTlsReadの呼び出しで受信できます。buffer_maxlenはINT_MAX (2147483647)を超えることはできません。

戻り値

成功の場合、読まれたバイト数。エラーの場合は -1 。

注意事項

関数の実行時にシステムソケットでエラーが発生した場合、SocketConnectによって確立された接続は中断されます。

データ読み込みエラーの場合は、エラー5273 (ERR_NETSOCKET_IO_ERROR)が _LastErrorに書かれます。

この関数は独自のスレッド内で実行されるエキスパートアドバイザーやスクリプトのみから呼び出すことが出来ます。指標から呼び出すと、GetLastError()はエラー4014「Function is not allowed for call(関数呼び出しの許可がありません)」を返します。

例:

//+------------------------------------------------------------------+
//|                                       SocketTlsReadAvailable.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link     "https://www.mql5.com
#property version     "1.00"
#property script_show_inputs
//+------------------------------------------------------------------+
//| スクリプトの入力                                                      |
//+------------------------------------------------------------------+
input string InpMethod ="GET";           // メソッド(HEAD,GET)
input string InpServer ="www.google.com"; // サーバ
input uint   InpPort   =443;             // ポート
input uint   InpTimeout=5000;             // タイムアウト
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数                                              |
//+------------------------------------------------------------------+
void OnStart(void)
 {
  Print("Server: ",InpServer);
  Print("Port: ",InpPort);
//--- ソケットを作成し、そのハンドルを取得する
  const int socket=SocketCreate();
 
  if(socket==INVALID_HANDLE)
    {
    Print("SocketCreate() failed. Error ",GetLastError());
    return;
    }
//--- ソケットシステムオブジェクトのデータの受信と送信のタイムアウトを設定する
  if(!SocketTimeouts(socket,InpTimeout,InpTimeout))
    {
    PrintFormat("SocketTimeouts(%u, %u) failed. Error %d",InpTimeout,InpTimeout,GetLastError());
    SocketClose(socket);
    return;
    }
//--- ポート経由でサーバーに接続する
  if(!SocketConnect(socket,InpServer,InpPort,InpTimeout))
    {
    PrintFormat("SocketConnect('%s', %u, %u) failed. Error %d",InpServer,InpPort,InpTimeout,GetLastError());
    SocketClose(socket);
    return;
    }
//--- ネットワーク接続を保護するために使用される証明書に関するデータを取得する
  string   subject,issuer,serial,thumbprint;
  datetime expiration;
 
  if(SocketTlsCertificate(socket,subject,issuer,serial,thumbprint,expiration))
    {
    Print("TLS certificate:");
    Print("   Owner:      ",subject);
    Print("   Issuer:     ",issuer);
    Print("   Number:     ",serial);
    Print("   Print:      ",thumbprint);
    Print("   Expiration: ",expiration);
    }
  else
    {
    //--- サーバーが証明書を提供していないため、安全でない接続を報告して終了する
    Print("The connection is not secured by a certificate");
    SocketClose(socket);
    return;
    }
//--- サーバにリクエストを送信する
  string request=StringFormat("%s / HTTP/1.1\r\nHost: %s\r\nUser-Agent: MetaTrader 5\r\n\r\n",InpMethod,InpServer);
 
  if(HTTPSendTLS(socket,request))
    {
    //--- リクエストが送信され、応答が返される
    Print("\nRequest sent. Starting page loading...");
    uchar response[]; // all received data (document header and body)
 
    if(!HTTPRecvTLS(socket,response,InpTimeout))
       {
        Print("There were errors while reading the page");
        SocketClose(socket);
        return;
       }
    //--- 受信したデータのバイト数を報告する
    PrintFormat("%u bytes received",response.Size());
    //--- 取得したページヘッダーのみを表示する
    string result    =CharArrayToString(response,0,WHOLE_ARRAY,CP_UTF8);
    int   header_end=StringFind(result,"\r\n\r\n");
 
    if(header_end>0)
       {
        Print("\nHTTP answer header received:");
        Print(StringSubstr(result,0,header_end));
       }
    }
//--- 使用後はソケットを閉じる</t1>
  SocketClose(socket);
  /*
   結果:
  Server: www.google.com
  Port: 443
  TLS certificate:
    Owner: /CN=www.google.com
    Issuer: /C=US/O=Google Trust Services/CN=WR2
    Number: 0d:43:b1:4a:bb:9c:15:96:10:e1:3d:55:23:9f:25:4e
    Print: 89167618e5017f813aff981c88ce422dc1016bdf
    Expiration: 2024.12.30 08:26:35
 
  Request sent. Starting page loading...
  HTTPRecvTLS: Document received within 27 attempts
  25185 bytes received
 
  HTTP answer header received:
  HTTP/1.1 200 OK
  Date: Fri, 25 Oct 2024 17:12:42 GMT
  Expires: -1
  Cache-Control: private, max-age=0
  Content-Type: text/html; charset=ISO-8859-1
  Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-CUL2rdUOeAN7xIV6v0WUuQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
  Accept-CH: Sec-CH-Prefers-Color-Scheme
  P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
  Server: gws
  X-XSS-Protection: 0
  X-Frame-Options: SAMEORIGIN
  Set-Cookie: AEC=AVYB7coyYMCdweTDTaWeGYzmRnxzKGqsOEosH_VkbCn8xhWkFz6v0kxQFw; expires=Wed, 23-Apr-2025 17:12:42 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax
  Set-Cookie: NID=518=J02X02Ff4v_9sMcNoUz-1SolmuG08E26Gs438ik0J_SOJUMy7of-P-qup-LaNSWVXUL8OjhOXpGIGuJQGIoEPBnzqDKCH-46_FN4J2foHeWTlGG8bVVvQ44AHWLg1OXjrGp3CUBexYdczLWNy3LxEcb7eh6mxSvFzOelPC6-vpXkaumLQ80x9gF_RpLcAYfN4ehT; expires=Sat, 26-Apr-2025 17:12:42 GMT; path=/; domain=.google.com; HttpOnly
  Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
  Accept-Ranges: none
  Vary: Accept-Encoding
  Transfer-Encoding: chunked
  */
 }
//+------------------------------------------------------------------+
//| 安全な接続を介して HTTP リクエストを送信する
//+------------------------------------------------------------------+
bool HTTPSendTLS(int socket,const string request)
 {
//--- 文字列を文字配列に変換し、終端のゼロを破棄する
  char req[];
  int len=StringToCharArray(request,req,0,WHOLE_ARRAY,CP_UTF8)-1;
 
  if(len<0)
    return false;
 
  return(SocketTlsSend(socket,req,len)==len);
 }
//+------------------------------------------------------------------+
//| 安全な接続を介して Web ページを取得する                                   |
//+------------------------------------------------------------------+
bool HTTPRecvTLS(int socket,uchar &response[],const uint timeout_ms)
 {
//--- タイムアウトが切れる前に、安全なTLS接続から利用可能なデータを読み取る
  ulong timeout_check=GetTickCount64()+timeout_ms;
  uchar block[1024];   // ソケットからブロックデータを読み取るためのバッファ
  uint attempt=0;     // 要求されたデータブロックの数
  int   err    =0;     // エラーコード
 
  ResetLastError();
 
  do
    {
    //--- ブロック単位で読み取り、最大1024バイト
    int len=SocketTlsReadAvailable(socket,block,1024);
 
    if(len>0)
       {
        attempt++;
        //--- 取得したデータブロックを結合する
        ArrayCopy(response,block,response.Size());
        //--- 取得したデータを分析し、ヘッダー、ページ本文、終了、読み込みエラーなどを定義する
        //...
        //...
        //...
        timeout_check=GetTickCount64()+timeout_ms;
       }
    else
        Sleep(10);
 
    err=GetLastError();
    }
  while(!IsStopped() && GetTickCount()<timeout_check && !err);
//--- 読み取り中にエラーは発生したか
  if(err)
    {
    Print("Error ",err);
    return(false);
    }
 
  PrintFormat("%s: Document received within %d attempts",__FUNCTION__,attempt);
  return(true);
 }

参照

SocketTimeoutsMathSwap