Diskussion zum Artikel "Communicating With MetaTrader 5 Using Named Pipes Without Using DLLs" - Seite 3

 
Renat:
Ich denke, dass die Kommunikation zwischen den Terminals nur einen kleinen Teil der Anwendung ausmacht.

Aber die Kommunikation mit externen Systemen ist wichtiger und anwendbar. Dafür wurde der sichere Kanal eröffnet.

Niemand bestreitet das, ich meine, die Erklärung, wozu das alles diente. Aber das Problem ist, wie es umgesetzt wurde. Schließlich sind externe Systeme nicht unbedingt in C geschrieben, sondern können in verschiedenen Programmiersprachen erstellt werden. Und eine Verbindung zum Terminal über einen benannten Kanal ist in vielen Programmiersprachen nur als Client über Dateioperationen möglich. Aber die Technologie wurde Client-Server gewählt, d.h. so, dass zwei Clients nicht aufeinander treffen, wenn es eine Lücke zwischen ihnen ohne eine Brücke - Gateway - gibt. D.h. es hätte entweder die Client-Client-Technologie oder ein Gateway vorgesehen werden müssen. Und so kam es wie in der Fabel "Der Fuchs und die Trauben" von Opa Krylow:

Auch wenn das Auge sieht,

aber das Auge kann nicht sehen.

© I. Krylow


Es war notwendig zu schauen, wie andere eine ähnliche Verbindung mit externen Systemen realisiert haben. Zum Beispiel: VMWare, MS SQL Server, MySQL, externe Modems und so weiter. Deren Serverteil ist intern implementiert. Und es ist sehr bequem, sich ohne Krücken zu verbinden, sogar über einen benannten Kanal, oder über TCP/IP und andere Kommunikationskanäle. Und Sie können sogar wählen, zum Beispiel, durch einen benannten Kanal, sondern remote über TCP / IP mit Hilfe von "Named Pipe TCP Proxy" Dienstprogramm. D.h. die Benutzer müssen keine zusätzlichen Krücken erstellen, sondern nur die am besten geeignete Client-Anwendung auswählen und sofort eine Verbindung herstellen und arbeiten.
 
Juri, Sie sind offensichtlich verwirrt. Server-Pipelines können leicht in anderen Sprachen erstellt werden. Es ist nur WinAPI.

Berücksichtigen Sie, dass MQL5 eine sichere Anwendungsumgebung ist, und zwar eindeutig eine Client-Umgebung, in der es unvernünftig ist, Serverfunktionen zu erstellen.

Ich bin mir nicht sicher, ob eine Serverfunktionalität deklariert wurde. Die Client-Funktionalität wurde geplant und implementiert.
 

Ich glaube, ich habe den Code für das Gateway erstellt. Ich habe es noch nicht getestet. Ich werde herunterladen und installieren MinGW und sehen, was falsch ist.

#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");
        // Erstellen Sie den ersten Unterprozess zum Kopieren von Informationen aus benannten Kanälen
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // Ausführen
        server->Start();
        Thread::Sleep(250);
        // Wenn der Client abgestürzt ist
        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) 
        {
            // Zwei benannte Kanäle erstellen
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // Wartet auf eine Verbindung vom Client
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // Kopieren Sie je nach Reihenfolge des Unterprozesses Daten von einem benannten Kanal in einen anderen.
          if (i == 0) {
            needclose = true;
            i++;
            // Erstellen Sie einen weiteren Unterprozess, um Informationen aus den genannten Kanälen auf den Zähler zu kopieren
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // Starten Sie den Unterprozess
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // Ausnahmehandler für gelöschte Clients 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

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

MinGW installiert, konfiguriert und mit NetBeans verbunden.

Die Idee, ein Vollduplex-Gateway aus zwei Serverkanälen zu erstellen und Informationen an Clients von einem Kanal zum anderen umzuleiten, hat nicht funktioniert. Wenn ein Server-Unterprozess einen Kanal liest und der zweite etwas dorthin sendet, funktioniert Vollduplex nicht (zumindest unter Windows XP), denn manchmal fängt der Unterprozess, der aus dem Kanal liest, Nachrichten von dem Unterprozess ab, der in denselben Kanal schreibt, und gibt die Informationen zurück.

Wenn Sie einen der Unterprozesse entfernen, läuft die Übertragung problemlos im Simplexverfahren von Client zu Client.

Es ist jedoch nicht alles verloren, denn es gibt auch einen überlappenden Modus, d. h. wenn nicht zwei, sondern nur ein Kanal erstellt wird und sich mehrere Clients gleichzeitig mit diesem verbinden. In diesem Fall muss der Server nicht ständig Informationen aus dem Kanal lesen, da alles auf Ereignissen basiert. Das heißt, wenn ein Client Informationen an den Kanal sendet, liest der Server dessen Ereignis und extrahiert daraus die übertragene Nachricht. Und die empfangenen Informationen an den zweiten Client weiterzuleiten - das ist schon eine Frage der Technik. Ich bin gerade dabei, eine solche Implementierung zu erstellen.

 

Das war's. Ich habe aufgegeben. Ich bin es leid, mich mit C++-Code und sogar mit der Win-API herumzuschlagen. Es geht nicht so sehr ums Programmieren, sondern darum, verstreute Informationsfetzen auf MSDN zu durchforsten, um zu verstehen, wie alles funktionieren soll. Da mir die Erfahrung fehlt, habe ich all diese Dinge an Service Work geschickt. Siehe Umgestaltung des C++-Codes in ein Zwei-Wege-Vollduplex-Gateway

Vielleicht kann jemand mit mehr Erfahrung diese Aufgabe leicht bewältigen? Ich schließe nicht aus, dass der Grund für die Fehler darin liegt, dass ich die Einstellungen der benannten Kanäle nicht herausfinden konnte. D.h. es ist möglich, dass man genau in diesen Einstellungen etwas richtig schreiben muss und alles funktioniert. Ich habe es bisher nicht geschafft, etwas anderes als im Simplex-Modus zu machen und zu starten.

 

Ich habe beschlossen, zu versuchen, Freundschaft zwischen MQL und AutoIt durch Pipelines zu machen.

Kurz gesagt, nur eine Harke, und überall :)

Nun, ich habe es geschafft, mit etwas Glück zu AutoIt zu übertragen, nur die ersten 4 Bytes mussten verworfen werden, da ist etwas "Müll". Was ist dieser "Müll"?

Dann habe ich versucht, nach MQL zu übertragen, hier ist es noch lustiger - es kommt gar nichts. Oder vielleicht organisiere ich die Übertragung nicht richtig.... Vielleicht liegt das ganze Problem in diesen 4 Bytes?

Was können Sie mir sagen?

 
fyords:

Ich habe beschlossen, zu versuchen, Freundschaft zwischen MQL und AutoIt durch Pipelines zu machen.

Kurz gesagt, nur eine Harke, und überall :)

Nun, ich habe es geschafft, mit etwas Glück zu AutoIt zu übertragen, nur die ersten 4 Bytes mussten verworfen werden, da ist etwas "Müll". Was ist dieser "Müll"?

Dann habe ich versucht, nach MQL zu übertragen, hier ist es noch lustiger - es kommt gar nichts. Oder vielleicht organisiere ich die Übertragung nicht richtig.... Vielleicht liegt das ganze Problem in diesen 4 Bytes?

Was können Sie mir sagen?

Sho, du auch?
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
Du bist also auch da drin?

Nein, ich bin hier.) Also, es war so:

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| Skript-Programmstartfunktion|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Warten auf Pipe-Server
   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");
//--- Willkommensnachricht senden
   string msg=__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__);
   //Drucken(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) ;//Erzeugt eine Instanz einer benannten Pipe
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;//Ermöglicht es einem Named-Pipe-Serverprozess, auf einen Client-Prozess zu warten, um eine Verbindung herzustellen
ConsoleWrite(ReadMsg($hwnd_pipe)) ;//Schreibt Daten in den STDOUT-Stream

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

Dieser Teil des Transfers von MQL zu AutoIt. Das funktioniert so.

Mit einem String aus Func ReadMsg($hPipe)

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

Ich esse die ersten 4 Bytes und alles funktioniert.

Frage: was enthalten diese ersten 4 Bytes?

 
fyords:

Ich habe die ersten 4 Bytes ausgelesen und alles funktioniert.

Frage: Was enthalten diese ersten 4 Bytes?

Bei der Übertragung von Zeichenketten kommen zuerst 4 Bytes ihrer Größe.
 
Dima_S:
Renat, wann ist es geplant, Pips in MT4 zu machen?
Sie wurden in der letzten Build von MetaTrader 4 gemacht.