Discusión sobre el artículo "Comunicándonos con Meta Trader 5 usando conexiones designadas sin utilizar DLL" - página 3

 
Renat:
Creo que el tema de la comunicación entre terminales tiene una pequeña proporción de aplicación.

Pero la comunicación con sistemas externos es más importante y aplicable. Para eso se abrió el canal seguro.

Nadie lo discute, es decir, la declaración de para qué servía. Pero el problema es cómo se implementó. Al fin y al cabo, los sistemas externos no están necesariamente escritos en C, sino que pueden crearse en distintos lenguajes de programación. Y es posible conectarse a la terminal a través de un canal con nombre en muchos lenguajes de programación sólo como cliente a través de operaciones de archivo. Pero la tecnología elegida fue cliente-servidor, es decir, de tal forma que dos clientes no se encontrarán si hay un hueco entre ellos sin un puente - pasarela. Es decir, se debería haber optado por la tecnología cliente-cliente o por una pasarela. Y así resultó como en la fábula del abuelo Krylov "La zorra y las uvas":

Aunque el ojo ve,

Pero el ojo no ve.

© I. Krylov


Era necesario observar cómo otros tienen una conexión similar con los sistemas externos realizados. Por ejemplo: VMWare, MS SQL Server, MySQL, módems externos y así sucesivamente. Su parte del servidor se implementa internamente. Y es muy conveniente para unirse sin muletas, incluso a través de un canal con nombre, oa través de TCP / IP y otros canales de comunicación. E incluso se puede elegir, por ejemplo, a través de un canal con nombre, pero de forma remota a través de TCP/IP con la ayuda de la utilidad "Named Pipe TCP Proxy". Es decir, los usuarios no necesitan crear ninguna muletilla adicional, sino sólo elegir la aplicación cliente más adecuada e inmediatamente conectarse y trabajar.
 
Yuri, estás claramente confundido. Los pipelines de servidor se pueden crear fácilmente en otros lenguajes. Es sólo WinAPI.

Ten en cuenta que MQL5 es un entorno de aplicación seguro, y claramente cliente, en el que no es razonable hacer funciones de servidor.

No estoy seguro de que la funcionalidad de servidor fuera declarada. La funcionalidad de cliente fue planeada e implementada.
 

Creo que hice el código para la pasarela. Todavía no lo he probado. Voy a descargar e instalar MinGW y ver lo que está mal.

#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");
        // Crear el primer subproceso para copiar la información de los canales nombrados
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // Ejecutarlo
        server->Start();
        Thread::Sleep(250);
        // Si el cliente se ha bloqueado
        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) 
        {
            // Crear dos canales con nombre
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // Esperando una conexión del cliente
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // Dependiendo del orden del subproceso, copia los datos de un canal con nombre a otro.
          if (i == 0) {
            needclose = true;
            i++;
            // Crear otro subproceso para copiar la información de los canales nombrados en el contador
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // Iniciar el subproceso
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // Manejador de excepciones para clientes caídos 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

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

MinGW instalado, configurado y atornillado a NetBeans.

La idea de crear una pasarela full-duplex a partir de dos canales de servidor y redirigir la información a los clientes de un canal a otro no funcionó. Si un subproceso del servidor lee un canal y el segundo le envía algo, el dúplex completo no funciona (al menos en Windows XP), porque a veces el subproceso que lee del canal intercepta los mensajes del subproceso que escribe en el mismo canal y devuelve la información.

Si quitas uno de los subprocesos, la transmisión va por simplex de cliente a cliente sin problemas.

Sin embargo, no todo está perdido, porque también existe un modo solapado, es decir, cuando no se crean dos, sino un solo canal, y varios clientes se conectan a él simultáneamente. En este caso, el servidor no necesita leer información del canal todo el tiempo, porque todo se basa en eventos. Es decir, si algún cliente envía información al canal, el servidor lee su evento y extrae de ahí el mensaje transmitido. Y redirigir la información recibida al segundo cliente - ya es una cuestión de técnica. Estoy en el proceso de crear tal implementación.

 

Ya está. Me he rendido. Estoy cansado de juguetear con código C++ e incluso a través de Win API. No tanto codificando como rebuscando entre retazos dispersos de información en MSDN para intentar entender cómo debería funcionar todo. Me falta experiencia, así que envié todo esto a Service Work. Ver Rehacer el código C++ en una pasarela bidireccional full duplex.

¿Quizás alguien con más experiencia pueda encargarse fácilmente de esta tarea? No descarto que la razón de los fallos es que no pude averiguar la configuración de los canales con nombre. Es decir, es posible que en estos mismos ajustes tenga que escribir algo correctamente y todo funcione. Hasta ahora no he conseguido hacer nada mas que en modo simplex y ejecutarlo.

 

Decidí tratar de hacer amistad entre MQL y AutoIt a través de tuberías.

En resumen, sólo un rastrillo, y en todas partes :)

Bueno, me las arreglé para transferir a AutoIt con un poco de suerte, sólo los primeros 4 bytes tuvo que ser descartado, hay un poco de "basura". ¿Qué es esta "basura"?

Luego traté de transferir a MQL, es aún más divertido aquí - nada viene en absoluto. O tal vez no organizo la transferencia correctamente.... ¿Tal vez todo el problema está en esos 4 bytes?

¿Qué me puede decir?

 
fyords:

Decidí tratar de hacer amistad entre MQL y AutoIt a través de tuberías.

En resumen, sólo un rastrillo, y en todas partes :)

Bueno, me las arreglé para transferir a AutoIt con un poco de suerte, sólo los primeros 4 bytes tuvo que ser descartado, hay un poco de "basura". ¿Qué es esta "basura"?

Luego traté de transferir a MQL, es aún más divertido aquí - nada viene en absoluto. O tal vez no organizo la transferencia correctamente.... ¿Tal vez todo el problema está en esos 4 bytes?

¿Qué me puede decir?

Sho, ¿tú también?
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
Entonces, ¿tú también estás ahí?

No, estoy aquí.) Entonces, fue así:

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| Función de inicio del programa de script|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- espera al servidor de tuberías
   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");
//--- enviar mensaje de bienvenida
   string msg=__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__);
   //Imprimir(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 una instancia de una tubería con nombre
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;//Habilita un proceso servidor de tuberías con nombre para que espere a que se conecte un proceso cliente.
ConsoleWrite(ReadMsg($hwnd_pipe)) ;//Escribe datos en el flujo 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) ;//EscribirMensaje
        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

Esta parte de la transferencia de MQL a AutoIt. Funciona por.

Con una cadena de Func ReadMsg($hPipe)

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

Me como los primeros 4 bytes y todo funciona.

Pregunta: ¿qué contienen estos primeros 4 bytes?

 
fyords:

Me como los 4 primeros bytes y todo funciona.

Pregunta: ¿qué contienen estos 4 primeros bytes?

Cuando se transmiten cadenas, los 4 bytes del tamaño de la cadena van primero.
 
Dima_S:
Renat, ¿cuándo está previsto hacer pips en MT4?
Se hicieron en la última versión de MetaTrader 4.