//+------------------------------------------------------------------+
//| 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
//+------------------------------------------------------------------+
//| Script inputs |
//+------------------------------------------------------------------+
input string InpMethod ="GET"; // Method (HEAD,GET)
input string InpServer ="www.google.com"; // Server
input uint InpPort =443; // Port
input uint InpTimeout=5000; // Timeouts
//+------------------------------------------------------------------+
//| 스크립트 프로그램 시작 함수 |
//+------------------------------------------------------------------+
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[]; //수신된 모든 데이터(문서 헤더 및 본문)
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));
}
}
//--- 사용 후 소켓 종료
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)
{
//--- 문자열을 문자 배열로 변환하고 종료 0을 버립니다.
char req[];
int len=StringToCharArray(request,req,0,WHOLE_ARRAY,CP_UTF8)-1;
if(len<0)
return false;
return(SocketTlsSend(socket,req,len)==len);
}
//+------------------------------------------------------------------+
//| 보안 연결을 통해 웹페이지 가져오기 |
//+------------------------------------------------------------------+
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);
}
|