Discussione sull’articolo "Comunicare con MetaTrader 5 utilizzando pipe denominate senza utilizzare DLL" - pagina 3

 
Renat:
Credo che la questione della comunicazione tra terminali abbia una piccola percentuale di applicazione.

Ma la comunicazione con i sistemi esterni è più importante e applicabile. È per questo che è stato aperto il canale sicuro.

Nessuno mette in discussione il fatto che sia stato dichiarato il suo scopo. Ma il problema è come è stato implementato. Dopo tutto, i sistemi esterni non sono necessariamente scritti in C, ma possono essere creati in diversi linguaggi di programmazione. E in molti linguaggi di programmazione è possibile connettersi al terminale attraverso un canale denominato solo come client attraverso operazioni su file. Ma la tecnologia scelta è quella client-server, cioè tale per cui due client non si incontrano se c'è una distanza tra loro senza un ponte - gateway. In altre parole, si sarebbe dovuto prevedere una tecnologia client-client o un gateway. E così è andata come nella favola di nonno Krylov "La volpe e l'uva":

Anche se l'occhio vede,

Ma l'occhio non vede.

© I. Krylov


È stato necessario osservare come altri hanno realizzato una connessione simile con i sistemi esterni. Ad esempio: VMWare, MS SQL Server, MySQL, modem esterni e così via. La loro parte server è implementata internamente. Ed è molto comodo unirsi senza stampelle, anche attraverso un canale denominato, o tramite TCP/IP e altri canali di comunicazione. È anche possibile scegliere, ad esempio, attraverso un canale denominato, ma in remoto via TCP/IP con l'aiuto dell'utility "Named Pipe TCP Proxy". In altre parole, gli utenti non devono creare stampelle aggiuntive, ma solo scegliere l'applicazione client più adatta e collegarsi e lavorare immediatamente.
 
Yuri, sei chiaramente confuso. Le pipeline server possono essere facilmente create in altri linguaggi. È solo WinAPI.

Tenete conto che MQL5 è un ambiente applicativo sicuro, e chiaramente un ambiente client, in cui è irragionevole creare funzioni server.

Non sono sicuro che la funzionalità server sia stata dichiarata. La funzionalità client è stata pianificata e implementata.
 

Credo di aver creato il codice per il gateway. Non l'ho ancora testato. Scaricherò e installerò MinGW e vedrò cosa c'è che non va.

#using <System.Core.dll>

using namespace System;
using namespace System::IO;
using namespace System::IO::Pipes;
using namespace System::Text;
using namespace System::Threading;


public ref class PipeServer
{
private:
       NamedPipeServerStream^ pipeServer1;
       NamedPipeServerStream^ pipeServer2;
    

public:
    static void Main()
    {
        int i;
        Thread server;

        Console::WriteLine("\n*** Named pipe server stream with impersonation example ***\n");
        Console::WriteLine("Waiting for client connect...\n");
        // Creare il primo sottoprocesso per copiare le informazioni dai canali denominati
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // Eseguirlo
        server->Start();
        Thread::Sleep(250);
        // Se il client si è bloccato
        if (servers != nullptr)
        {
          if (server->Join(250))
                                        {
            Console::WriteLine("Server finished.", server->ManagedThreadId);
            servers = nullptr;
          }
        }
        Console::WriteLine("\nServer threads exhausted, exiting.");
    }

private:
    static void ServerThread()
    {
        int threadId;
        bool needclose = false;
        if (i == 0) 
        {
            // Creare due canali denominati
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // In attesa di una connessione dal client
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // A seconda dell'ordine del sottoprocesso, copiare i dati da un canale denominato a un altro.
          if (i == 0) {
            needclose = true;
            i++;
            // Creare un altro sottoprocesso per copiare le informazioni dai canali nominati sul contatore
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // Avviare il sottoprocesso
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // Gestore delle eccezioni per i client abbandonati 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

int main()
{
    PipeServer::Main();
}
 

MinGW è stato installato, configurato e collegato a NetBeans.

L'idea di creare un gateway full-duplex da due canali server e di reindirizzare le informazioni ai client da un canale all'altro non ha funzionato. Se un sottoprocesso del server legge un canale e il secondo gli invia qualcosa, il full duplex non funziona (almeno su Windows XP), perché a volte il sottoprocesso che legge dal canale intercetta i messaggi del sottoprocesso che scrive sullo stesso canale e restituisce le informazioni.

Se si rimuove uno dei sottoprocessi, la trasmissione avviene in simplex da client a client senza problemi.

Tuttavia, non tutto è perduto, perché esiste anche una modalità sovrapposta, cioè quando non vengono creati due canali, ma uno solo, e diversi client vi si connettono contemporaneamente. In questo caso il server non ha bisogno di leggere continuamente le informazioni dal canale, perché tutto si basa sugli eventi. Cioè, se un client invia informazioni al canale, il server legge il suo evento e ne estrae il messaggio trasmesso. E reindirizzare le informazioni ricevute al secondo client è già una questione di tecnica. Sono in procinto di creare un'implementazione di questo tipo.

 

È così. Mi sono arreso. Sono stanco di armeggiare con il codice C++ e persino con le API di Win. Non tanto di codificare, quanto di scavare tra gli sparsi frammenti di informazioni su MSDN per cercare di capire come tutto dovrebbe funzionare. Manca l'esperienza, quindi ho inviato tutto questo materiale a Service Work. Vedere Rifare il codice C++ in un gateway full duplex bidirezionale.

Forse qualcuno più esperto può gestire facilmente questo compito? Non escludo che la ragione del fallimento sia che non sono riuscito a capire le impostazioni dei canali denominati. Cioè è possibile che proprio in queste impostazioni sia necessario scrivere qualcosa di corretto e che tutto funzioni. Finora non sono riuscito a fare nulla se non in modalità simplex e a farlo funzionare.

 

Ho deciso di provare a fare amicizia tra MQL e AutoIt attraverso le pipeline.

In breve, un solo rastrello, e ovunque :)

Bene, sono riuscito a trasferire il file in AutoIt con un po' di fortuna, solo i primi 4 byte dovevano essere scartati, c'è un po' di "spazzatura". Cos'è questa "spazzatura"?

Poi ho provato a trasferire in MQL, ma qui è ancora più divertente: non arriva nulla. O forse non organizzo correttamente il trasferimento.... Forse il problema sta tutto in quei 4 byte?

Cosa puoi dirmi?

 
fyords:

Ho deciso di provare a fare amicizia tra MQL e AutoIt attraverso le pipeline.

In breve, un solo rastrello, e ovunque :)

Bene, sono riuscito a trasferire il file in AutoIt con un po' di fortuna, solo i primi 4 byte dovevano essere scartati, c'è un po' di "spazzatura". Cos'è questa "spazzatura"?

Poi ho provato a trasferire in MQL, ma qui è ancora più divertente: non arriva nulla. O forse non organizzo correttamente il trasferimento.... Forse il problema sta tutto in quei 4 byte?

Cosa puoi dirmi?

Sho, anche tu?
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
Quindi, anche tu sei lì dentro?

No, sono qui). Quindi, era così:

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| Funzione di avvio del programma di script|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- attendere il server pipe
   while(!IsStopped())
     {
      if(ExtPipe.Open("\\\\.\\pipe\\MQL5.Pipe.Server",FILE_READ|FILE_WRITE|FILE_BIN|FILE_ANSI)!=INVALID_HANDLE) break;
      Sleep(250);
     }
   Print("Client: pipe opened");
//--- inviare un messaggio di benvenuto
   string msg=__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__);
   //Stampa(msg);
   
   if(!ExtPipe.WriteString(msg))
     {
      Print("Client: sending welcome message failed");
      return;
     }
  }

AutoIt

#include <NamedPipes.au3>
#include <WinAPI.au3>

$pipe="\\.\pipe\MQL5.Pipe.Server"
$hwnd_pipe=_NamedPipes_CreateNamedPipe($pipe) ;//Crea un'istanza di un tubo denominato
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;/Abilita un processo server named pipe ad attendere la connessione di un processo client
ConsoleWrite(ReadMsg($hwnd_pipe)) ;/Scrive i dati sul flusso STDOUT

Func ReadMsg($hPipe) ;//Leggere il messaggio
        Local $bSuccess, $iRead, $pBuffer, $tBuffer, $BUFSIZE=4096

        $tBuffer = DllStructCreate("char Text[4096]")
        $pBuffer = DllStructGetPtr($tBuffer)
        _WinAPI_ReadFile($hPipe, $pBuffer, 4, $iRead, 0)
        While 1
                $bSuccess = _WinAPI_ReadFile($hPipe, $pBuffer, $BUFSIZE, $iRead, 0)
                If $iRead = 0 Then ExitLoop
                If Not $bSuccess Or (_WinAPI_GetLastError() = 234) Then ExitLoop
                Return StringLeft(DllStructGetData($tBuffer, "Text"), $iRead)
        WEnd
 EndFunc
 
 Func WriteMsg($hPipe,$sMessage) ;//ScrivereMsg
        Local $iWritten, $iBuffer, $pBuffer, $tBuffer

        $iBuffer = StringLen($sMessage) + 1
        $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]")
        $pBuffer = DllStructGetPtr($tBuffer)
        DllStructSetData($tBuffer, "Text", $sMessage)
        If Not _WinAPI_WriteFile($hPipe, $pBuffer, $iBuffer, $iWritten, 0) Then
                LogError("WriteMsg: _WinAPI_WriteFile failed")
        EndIf
EndFunc

Questa parte del trasferimento da MQL ad AutoIt. Funziona con.

Con una stringa da Func ReadMsg($hPipe)

_WinAPI_ReadFile($hPipe, $pBuffer, 4, $iRead, 0)

Mangio i primi 4 byte e tutto funziona.

Domanda: cosa contengono questi primi 4 byte?

 
fyords:

Ho eliminato i primi 4 byte e tutto funziona.

Domanda: cosa contengono questi primi 4 byte?

Quando si trasmettono stringhe, i 4 byte della loro dimensione vengono prima.
 
Dima_S:
Renat, quando è prevista la creazione di pip in MT4?
Sono stati creati nell'ultima build di MetaTrader 4.