English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
DLL'leri Kullanmadan Adlandırılmış Kanalları Kullanarak MetaTrader 5 ile İletişim Kurma

DLL'leri Kullanmadan Adlandırılmış Kanalları Kullanarak MetaTrader 5 ile İletişim Kurma

MetaTrader 5Örnekler | 22 Aralık 2021, 15:12
313 1
MetaQuotes
MetaQuotes

Giriş

Birçok geliştirici aynı sorunla karşı karşıyadır: Güvenli olmayan DLL'ler kullanmadan alım satım terminali korumalı alanına nasıl ulaşılır?

En kolay ve en güvenli yöntemlerden biri, normal dosya işlemleri gibi çalışan standart Adlandırılmış Kanalları kullanmaktır. Bunlar, programlar arasında işlemciler arası istemci-sunucu iletişimini düzenlemenize olanak tanır. Bu konuda, yani DLL'lere erişimin mümkün olduğunu gösteren halihazırda yayınlanmış bir makale olmasına rağmen Adlandırılmış Kanalları kullanarak MetaTrader 5 terminalleri arasında iletişim kurmak için DLL içermeyen bir çözüm, istemci terminalinin standart ve güvenli özelliklerini kullanacağız.

Adlandırılmış kanallar hakkında daha fazla bilgiyi MSDN kitaplığında bulabilirsiniz, ancak biz pratik C++ ve MQL5 örneklerine geçeceğiz. Aralarında sunucu, istemci, veri alışverişi uygulayacağız ve ardından performansı kıyaslayacağız.


Sunucu Uygulaması

Basit bir sunucuyu C++ ile kodlayalım. Terminalden bir script dosyası bu sunucuya bağlanacak ve onunla veri alışverişi yapacaktır. Sunucu çekirdeği aşağıdaki WinAPI işlevlerine sahiptir:

Adlandırılmış bir kanal açıldığında, normal okuma/yazma dosya işlemleri için kullanılabilecek bir dosya tanıtıcısını döndürür. Sonuç olarak, ağ işlemlerinde herhangi bir özel bilgi gerektirmeyen çok basit bir mekanizma elde edersiniz.

Adlandırılmış kanalların bir ayırt edici özelliği vardır; bunlar hem yerel hem de ağ olabilir. Yani, istemci terminallerinden ağ bağlantılarını kabul edecek bir uzak sunucu uygulamak kolaydır.

Bayt değişim modunda çalışan tam çift yönlü kanal olarak yerel bir sunucu oluşturmaya ilişkin basit bir örnek şu şekildedir:

//--- open 
CPipeManager manager;

if(!manager.Create(L"\\\\.\\pipe\\MQL5.Pipe.Server"))
   return(-1);


//+------------------------------------------------------------------+
//| Create named pipe                                                |
//+------------------------------------------------------------------+
bool CPipeManager::Create(LPCWSTR pipename)
  {
//--- check parameters
   if(!pipename || *pipename==0) return(false);
//--- close old
   Close();
//--- create named pipe
   m_handle=CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX,
                            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                            PIPE_UNLIMITED_INSTANCES,256*1024,256*1024,1000,NULL);

   if(m_handle==INVALID_HANDLE_VALUE)
     {
      wprintf(L"Creating pipe '%s' failed\n",pipename);
      return(false);
     }
//--- ok
   wprintf(L"Pipe '%s' created\n",pipename);
   return(true);
  }

İstemci bağlantısı almak için ConnectNamedPipe işlevini kullanmanız gerekir:

//+------------------------------------------------------------------+
//| Connect client                                                   |
//+------------------------------------------------------------------+
bool CPipeManager::ConnectClient(void)
  {
//--- pipe exists?
   if(m_handle==INVALID_HANDLE_VALUE) return(false);
//--- connected?
   if(!m_connected)
     {
      //--- connect
      if(ConnectNamedPipe(m_handle,NULL)==0)
        {
         //--- client already connected before ConnectNamedPipe?
         if(GetLastError()!=ERROR_PIPE_CONNECTED)
            return(false);
         //--- ok
        }
      m_connected=true;
     }
//---
   return(true);
  }

Veri alışverişi, 4 basit işlev kullanılarak düzenlenir:

  • CPipeManager::Send(void *data,size_t data_size)
  • CPipeManager::Read(void *data,size_t data_size)
  • CPipeManager::SendString(LPCSTR command)
  • CPipeManager::ReadString(LPSTR answer,size_t answer_maxlen)

MQL5 uyumlu modda verileri ikili veri veya ANSI metin dizeleri olarak göndermenize/almanıza olanak tanır. Ayrıca, MQL5'teki CFilePipe bir dosyayı varsayılan olarak ANSI modunda açtığı için, alınıp gönderilirken dizeler otomatik olarak Unicode'a dönüştürülür. MQL5 programınız Unicode modunda (FILE_UNICODE) bir dosya açarsa, Unicode dizelerini değiştirebilir (BOM başlangıç imzasıyla).


İstemci Uygulaması

İstemcimizi MQL5'te yazacağız. Bu, Standart Kitaplık'tan CFilePipe sınıfını kullanarak normal dosya işlemlerini gerçekleştirebilecektir. Bu sınıf, CFileBin ile neredeyse aynıdır, ancak bu verileri okumadan önce bir sanal dosyada veri kullanılabilirliğinin önemli bir doğrulamasını içerir.

//+------------------------------------------------------------------+
//| Wait for incoming data                                           |
//+------------------------------------------------------------------+
bool CFilePipe::WaitForRead(const ulong size)
  {
//--- check handle and stop flag
   while(m_handle!=INVALID_HANDLE && !IsStopped())
     {
      //--- enough data?
      if(FileSize(m_handle)>=size)
         return(true);
      //--- wait a little
      Sleep(1);
     }
//--- failure
   return(false);
  }

//+------------------------------------------------------------------+
//| Read an array of variables of double type                        |
//+------------------------------------------------------------------+
uint CFilePipe::ReadDoubleArray(double &array[],const int start_item,const int items_count)
  {
//--- calculate size
   uint size=ArraySize(array);
   if(items_count!=WHOLE_ARRAY) size=items_count;
//--- check for data
   if(WaitForRead(size*sizeof(double)))
      return FileReadArray(m_handle,array,start_item,items_count);
//--- failure
   return(0);
  }

Adlandırılmış kanallar, yerel ve ağ modlarının uygulanmasında önemli farklılıklara sahiptir. Böyle bir doğrulama olmadan, büyük miktarda veri (64K üzeri) gönderirken ağ modu işlemleri her zaman bir okuma hatası döndürecektir.

Sunucuya iki kontrol ile bağlanalım: Ya 'RemoteServerName' adlı uzak bilgisayara ya da yerel makineye.

void OnStart()
  {
//--- wait for pipe server
   while(!IsStopped())
     {
      if(ExtPipe.Open("\\\\RemoteServerName\\pipe\\MQL5.Pipe.Server",FILE_READ|FILE_WRITE|FILE_BIN)!=INVALID_HANDLE) break;
      if(ExtPipe.Open("\\\\.\\pipe\\MQL5.Pipe.Server",FILE_READ|FILE_WRITE|FILE_BIN)!=INVALID_HANDLE) break;
      Sleep(250);
     }
   Print("Client: pipe opened");


Veri Alışverişi

Başarılı bir bağlantıdan sonra, sunucuya tanımlama bilgilerini içeren bir metin dizesi gönderelim. Dosya ANSI modunda açıldığı için, Unicode dizesi otomatik olarak ANSI'ye dönüştürülecektir.

//--- send welcome message
   if(!ExtPipe.WriteString(__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__)))
     {
      Print("Client: sending welcome message failed");
      return;
     }

Yanıt olarak, sunucu "Kanal sunucusundan merhaba" dizesini ve 1234567890 tamsayısını gönderecektir. İstemci bir kez daha "Test dizesi" dizesini ve 1234567890 tamsayısını gönderecektir.

//--- read data from server
   string        str;
   int           value=0;

   if(!ExtPipe.ReadString(str))
     {
      Print("Client: reading string failed");
      return;
     }
   Print("Server: ",str," received");

   if(!ExtPipe.ReadInteger(value))
     {
      Print("Client: reading integer failed");
      return;
     }
   Print("Server: ",value," received");
//--- send data to server
   if(!ExtPipe.WriteString("Test string"))
     {
      Print("Client: sending string failed");
      return;
     }

   if(!ExtPipe.WriteInteger(value))
     {
      Print("Client: sending integer failed");
      return;
     }

Evet, basit veri alışverişini bitirdik. Şimdi performans karşılaştırması yapma zamanı.


Performans Karşılaştırması

Test etmek için, sunucudan istemciye 8 megabaytlık bloklar halinde çift tür sayıların bir dizisi olarak 1 gigabayt veri göndereceğiz, ardından blokların doğruluğunu kontrol edecek ve aktarım hızını ölçeceğiz.

C++ sunucusundaki bu kod şu şekildedir:

//--- benchmark
   double  volume=0.0;
   double *buffer=new double[1024*1024];   // 8 Mb

   wprintf(L"Server: start benchmark\n");
   if(buffer)
     {
      //--- fill the buffer
      for(size_t j=0;j<1024*1024;j++)
         buffer[j]=j;
      //--- send 8 Mb * 128 = 1024 Mb to client
      DWORD   ticks=GetTickCount();

      for(size_t i=0;i<128;i++)
        {
         //--- setup guard signatures
         buffer[0]=i;
         buffer[1024*1024-1]=i+1024*1024-1;
         //--- 
         if(!manager.Send(buffer,sizeof(double)*1024*1024))
           {
            wprintf(L"Server: benchmark failed, %d\n",GetLastError());
            break;
           }
         volume+=sizeof(double)*1024*1024;
         wprintf(L".");
        }
      wprintf(L"\n");
      //--- read confirmation
      if(!manager.Read(&value,sizeof(value)) || value!=12345)
         wprintf(L"Server: benchmark confirmation failed\n");
      //--- show statistics
      ticks=GetTickCount()-ticks;
      if(ticks>0)
         wprintf(L"Server: %.0lf Mb sent at %.0lf Mb per second\n",volume/1024/1024,volume/1024/ticks);
      //---
      delete[] buffer;
     }

ve MQL5 istemcisindeki:

//--- benchmark
   double buffer[];
   double volume=0.0;

   if(ArrayResize(buffer,1024*1024,0)==1024*1024)
     {
      uint  ticks=GetTickCount();
      //--- read 8 Mb * 128 = 1024 Mb from server
      for(int i=0;i<128;i++)
        {
         uint items=ExtPipe.ReadDoubleArray(buffer);
         if(items!=1024*1024)
           {
            Print("Client: benchmark failed after ",volume/1024," Kb, ",items," items received");
            break;
           }
         //--- check the data
         if(buffer[0]!=i || buffer[1024*1024-1]!=i+1024*1024-1)
           {
            Print("Client: benchmark invalid content");
            break;
           }
         //---
         volume+=sizeof(double)*1024*1024;
        }
      //--- send confirmation
      value=12345;
      if(!ExtPipe.WriteInteger(value))
         Print("Client: benchmark confirmation failed ");
      //--- show statistics
      ticks=GetTickCount()-ticks;
      if(ticks>0)
         printf("Client: %.0lf Mb received at %.0lf Mb per second\n",volume/1024/1024,volume/1024/ticks);
      //---
      ArrayFree(buffer);
     }

Aktarım sırasında herhangi bir hata olmadığından emin olmak için aktarılan blokların ilk ve son öğelerinin kontrol edildiğini unutmayın. Ayrıca, aktarım tamamlandığında, istemci sunucuya başarılı veri alımı hakkında bir onay sinyali gönderir. Son onayları kullanmazsanız, taraflardan biri bağlantıyı çok erken kapatırsa kolayca veri kaybıyla karşılaşırsınız.

PipeServer.exe sunucusunu yerel olarak çalıştırın ve PipeClient.mq5 script dosyasını herhangi bir grafiğe ekleyin:

PipeServer.exe PipeClient.mq5
MQL5 Pipe Server
Copyright 2012, MetaQuotes Software Corp.
Pipe '\\.\pipe\MQL5.Pipe.Server' created
Client: waiting for connection...
Client: connected as 'PipeClient.mq5 on MQL5 build 705'
Server: send string
Server: send integer
Server: read string
Server: 'Test string' received
Server: read integer
Server: 1234567890 received
Server: start benchmark
......................................................
........
Server: 1024 Mb sent at 2921 Mb per second
PipeClient (EURUSD,H1)  Client: pipe opened
PipeClient (EURUSD,H1)  Server: Hello from pipe server received
PipeClient (EURUSD,H1)  Server: 1234567890 received
PipeClient (EURUSD,H1)  Client: 1024 Mb received at 2921 Mb per second


Yerel alışveriş için aktarım hızı gerçekten şaşırtıcı; saniyede neredeyse 3 gigabayt. Bu, hemen hemen her miktarda veriyi MQL5 programlarına aktarmak için adlandırılmış kanalların kullanılabileceği anlamına gelir.

Şimdi sıradan bir 1 gigabit LAN'da veri aktarım performansını karşılaştıralım:

PipeServer.exe PipeClient.mq5
MQL5 Pipe Server
Copyright 2012, MetaQuotes Software Corp.
Pipe '\\.\pipe\MQL5.Pipe.Server' created
Client: waiting for connection...
Client: connected as 'PipeClient.mq5 on MQL5 build 705'
Server: send string
Server: send integer
Server: read string
Server: 'Test string' received
Server: read integer
Server: 1234567890 received
Server: start benchmark
......................................................
........
Server: 1024 Mb sent at 63 Mb per second
PipeClient (EURUSD,H1)  Client: pipe opened
PipeClient (EURUSD,H1)  Server: Hello from pipe server received
PipeClient (EURUSD,H1)  Server: 1234567890 received
PipeClient (EURUSD,H1)  Client: 1024 Mb received at 63 Mb per second


Yerel ağda saniyede 63 megabayt hızında 1 gigabayt veri aktarıldı; bu çok iyi. Aslında, bu, gigabit ağının maksimum bant genişliğinin %63'üdür.


Sonuç

MetaTrader 5 alım satım platformunun koruma sistemi, MQL5 programlarının korumalı alanlarının dışında çalışmasına izin vermez ve yatırımcıları güvenilmeyen Expert Advisor'ları kullanırken tehditlere karşı korur. Adlandırılmış kanalları kullanarak, üçüncü taraf yazılımlarla kolayca entegrasyonlar oluşturabilir ve EA'ları dışarıdan yönetebilirsiniz. Güvenli bir şekilde.

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/503

Ekli dosyalar |
pipeclient.mq5 (3.15 KB)
pipeserver.zip (43.59 KB)
Son yorumlar | Tartışmaya git (1)
Pahlavon Tursunaliyev
Pahlavon Tursunaliyev | 11 Tem 2022 şu zamanda: 00:59
Salom
Alım Satım Sinyallerine Nasıl Abone Olunur? Alım Satım Sinyallerine Nasıl Abone Olunur?
Sinyaller hizmeti, MetaTrader 4 ve MetaTrader 5 ile sosyal alım satımı tanıtmaktadır. Hizmet, alım satım platformuna entegre edilmiştir ve herkesin profesyonel yatırımcıların alım satım işlemlerini kolaylıkla kopyalamasına olanak tanır. Binlerce sinyal sağlayıcıdan herhangi birini seçin ve birkaç tıklamayla abone olun; sağlayıcının alım satım işlemleri hesabınıza kopyalanacaktır.
Diğer Uygulamalar için MetaTrader 5 Fiyat Teklifleri Nasıl Hazırlanır? Diğer Uygulamalar için MetaTrader 5 Fiyat Teklifleri Nasıl Hazırlanır?
Makalede, dizin oluşturma, veri kopyalama, dosyalama, Piyasa İzleme'deki veya ortak listedeki sembollerle çalışma örneklerinin yanı sıra işleme hataları vb. örnekler açıklanmaktadır. Tüm bu öğeler, sonunda, verileri kullanıcı tanımlı bir biçimde dosyalamak için tek bir script dosyasında toplanabilir.
Market Ürünü İçin İyi Bir Açıklama Nasıl Yazılır? Market Ürünü İçin İyi Bir Açıklama Nasıl Yazılır?
MQL5 Market'ta birçok satılık ürün mevcut, ancak bazılarına ilişkin açıklamalar çok yetersiz olabiliyor. Sıradan yatırımcılar bunları anlayamadığı için, pek çok metin açıkça geliştirilmeye ihtiyaç duyuyor. Bu makale, ürününüzü olumlu bir ışık altında tutmanıza yardımcı olacaktır. Müşterilerinize tam olarak ne sattığınızı kolayca gösterebilecek dikkat çekici bir açıklama yazmak için önerilerimizden yararlanın.
MetaTrader Market'tan bir alım satım robotu nasıl satın alınır ve yüklenir? MetaTrader Market'tan bir alım satım robotu nasıl satın alınır ve yüklenir?
MetaTrader Market'tan bir ürün, MQL5.com web sitesinden veya doğrudan MetaTrader 4 ve MetaTrader 5 alım satım platformlarından satın alınabilir. Alım satım tarzınıza uygun bir ürün seçin, tercih ettiğiniz ödeme yöntemini kullanarak ödeme yapın ve ürünü etkinleştirin.