Discussion de l'article "Communiquer avec MetaTrader 5 en utilisant Named Pipes sans utiliser de DLL" - page 3

 
Renat:
Je pense que la question de la communication entre les terminaux n'a qu'un faible taux d'application.

En revanche, la communication avec les systèmes externes est plus importante et plus applicable. C'est pour cela que le canal sécurisé a été ouvert.

Personne ne conteste cela, je veux dire, la déclaration de l'objectif. Mais le problème réside dans la manière dont il a été mis en œuvre. Après tout, les systèmes externes ne sont pas nécessairement écrits en C, mais peuvent être créés dans différents langages de programmation. Et il est possible de se connecter au terminal par le biais d'un canal nommé dans de nombreux langages de programmation uniquement en tant que client par le biais d'opérations sur les fichiers. Mais la technologie choisie est celle du client-serveur, c'est-à-dire que deux clients ne se rencontreront pas s'il y a un fossé entre eux sans passerelle. En d'autres termes, il aurait fallu prévoir soit une technologie client-client, soit une passerelle. Et c'est ainsi que les choses se sont passées, comme dans la fable de grand-père Krylov "Le renard et les raisins" :

Même si l'œil voit,

Mais l'œil ne peut pas voir.

I. Krylov


Il a été nécessaire d'examiner comment d'autres personnes ont réalisé une connexion similaire avec des systèmes externes. Par exemple : VMWare, MS SQL Server, MySQL, modems externes, etc. La partie serveur est mise en œuvre en interne. Et il est très pratique de s'y connecter sans aucune béquille, même par le biais d'un canal nommé, ou via TCP/IP et d'autres canaux de communication. Vous pouvez même choisir, par exemple, un canal nommé, mais à distance via TCP/IP à l'aide de l'utilitaire "Named Pipe TCP Proxy". En d'autres termes, les utilisateurs n'ont pas besoin de créer des béquilles supplémentaires, ils n'ont qu'à choisir l'application client la plus appropriée et à se connecter et travailler immédiatement.
 
Yuri, vous êtes manifestement confus. Les pipelines de serveur peuvent être facilement créés dans d'autres langages. Il s'agit simplement de WinAPI.

Tenez compte du fait que MQL5 est un environnement d'application sécurisé, et clairement un environnement client, dans lequel il n'est pas raisonnable de créer des fonctions serveur.

Je ne suis pas sûr que la fonctionnalité serveur ait été déclarée. La fonctionnalité client a été planifiée et mise en œuvre.
 

Je crois que j'ai fait le code pour la passerelle. Je ne l'ai pas encore testé. Je vais télécharger et installer MinGW et voir ce qui ne va pas.

#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");
        // Créer le premier sous-processus pour copier les informations des canaux nommés
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // Exécuter
        server->Start();
        Thread::Sleep(250);
        // Si le client s'est écrasé
        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) 
        {
            // Créer deux canaux nommés
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // Attente d'une connexion de la part du client
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // En fonction de l'ordre du sous-processus, copier les données d'un canal nommé vers un autre.
          if (i == 0) {
            needclose = true;
            i++;
            // Créer un autre sous-processus pour copier les informations des canaux nommés sur le compteur
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // Démarrage du sous-processus
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // Gestionnaire d'exception pour les clients abandonnés 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

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

MinGW installé, configuré et boulonné à NetBeans.

L'idée de créer une passerelle full-duplex à partir de deux canaux de serveur et de rediriger les informations vers les clients d'un canal à l'autre n'a pas fonctionné. Si un sous-processus du serveur lit un canal et que le second lui envoie quelque chose, le duplex intégral ne fonctionne pas (du moins sous Windows XP), car il arrive que le sous-processus qui lit le canal intercepte les messages du sous-processus qui écrit sur le même canal et renvoie l'information.

Si vous supprimez l'un des sous-processus, la transmission se fait en simplex de client à client sans aucun problème.

Cependant, tout n'est pas perdu, car il existe également un mode superposé, c'est-à-dire lorsque non pas deux, mais un seul canal est créé, et que plusieurs clients s'y connectent simultanément. Dans ce cas, le serveur n'a pas besoin de lire les informations du canal en permanence, car tout est basé sur des événements. En d'autres termes, si un client envoie des informations au canal, le serveur lit son événement et en extrait le message transmis. Et pour rediriger les informations reçues vers le deuxième client, c'est déjà une question de technique. Je suis en train de créer une telle implémentation.

 

Voilà, c'est fait. J'ai abandonné. Je suis fatigué de jouer avec le code C++ et même avec Win API. Ce n'est pas tant du codage que de la recherche d'informations éparses sur MSDN pour essayer de comprendre comment tout devrait fonctionner. Comme je manque d'expérience, j'ai envoyé tout cela à Service Work. Voir Refaire le code C++ pour en faire une passerelle bidirectionnelle full duplex.

Peut-être que quelqu'un de plus expérimenté peut facilement s'occuper de cette tâche ? Je n'exclus pas que la raison des échecs soit que je n'ai pas pu comprendre les paramètres des canaux nommés. Il est possible qu'il faille écrire quelque chose de correct dans ces paramètres et que tout fonctionne. Jusqu'à présent, je n'ai pas réussi à faire autre chose qu'en mode simplex et à le faire fonctionner.

 

J'ai décidé d'essayer de faire l'amitié entre MQL et AutoIt à travers des pipelines.

En bref, un seul râteau, et partout :)

Bon, j'ai réussi à transférer vers AutoIt avec un peu de chance, seuls les 4 premiers octets ont dû être jetés, il y a des "déchets". Qu'est-ce que c'est que ces "déchets" ?

Ensuite, j'ai essayé de transférer vers MQL, c'est encore plus amusant ici - rien ne vient du tout. Ou peut-être que je n'organise pas correctement le transfert.... Peut-être que tout le problème réside dans ces 4 octets ?

Que pouvez-vous me dire ?

 
fyords:

J'ai décidé d'essayer de faire l'amitié entre MQL et AutoIt à travers des pipelines.

En bref, un seul râteau, et partout :)

Bon, j'ai réussi à transférer vers AutoIt avec un peu de chance, seuls les 4 premiers octets ont dû être jetés, il y a des "déchets". Qu'est-ce que c'est que ces "déchets" ?

Ensuite, j'ai essayé de transférer vers MQL, c'est encore plus amusant ici - rien ne vient du tout. Ou peut-être que je n'organise pas correctement le transfert.... Peut-être que tout le problème réside dans ces 4 octets ?

Que pouvez-vous me dire ?

Sho, vous aussi?
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
Alors, vous êtes là-dedans aussi ?

Non, je suis juste là.) Donc, c'était comme ça :

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| Fonction de démarrage du programme de script|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- attendre le serveur de 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");
//--- envoyer un message de bienvenue
   string msg=__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__);
   //Imprimer(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) ;/Création d'une instance d'un tuyau nommé
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;//Autorise un processus serveur à pipe nommée à attendre qu'un processus client se connecte
ConsoleWrite(ReadMsg($hwnd_pipe)) ;//Écrit les données dans le flux STDOUT

Func ReadMsg($hPipe) ;//ReadMsg
        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) ;//WriteMsg
        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

Cette partie du transfert de MQL à AutoIt. Elle fonctionne de la manière suivante.

Avec une chaîne de Func ReadMsg($hPipe)

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

Je mange les 4 premiers octets et tout fonctionne.

Question : que contiennent ces 4 premiers octets ?

 
fyords:

J'ai mangé les 4 premiers octets et tout fonctionne.

Question : que contiennent ces 4 premiers octets ?

Lors de la transmission d'une chaîne de caractères, les 4 premiers octets de sa taille sont transmis en premier.
 
Dima_S:
Renat, quand est-il prévu de faire des pips dans MT4 ?
Ils ont été créés dans la dernière version de MetaTrader 4.