Discussão do artigo "Comunicando-se com o MetaTrader 5 utilizando pipes nomeados sem DLLs" - página 3

 
Renat:
Acho que a questão da comunicação entre terminais tem uma pequena proporção de aplicação.

Mas a comunicação com sistemas externos é mais importante e aplicável. É para isso que o canal seguro foi aberto.

Ninguém está discutindo isso, quero dizer, a declaração de que era para isso. Mas o problema é como ele foi implementado. Afinal de contas, os sistemas externos não são necessariamente escritos em C, mas podem ser criados em diferentes linguagens de programação. E é possível conectar-se ao terminal por meio de um canal nomeado em muitas linguagens de programação apenas como um cliente por meio de operações de arquivo. Mas a tecnologia escolhida foi cliente-servidor, ou seja, de modo que dois clientes não se encontrem se houver uma lacuna entre eles sem uma ponte - gateway. Ou seja, deveria ter sido fornecida a tecnologia cliente-cliente ou um gateway. E foi assim que aconteceu, como na fábula do avô Krylov "A raposa e as uvas":

Mesmo que o olho veja,

Mas o olho não pode ver.

© I. Krylov


Foi necessário observar como outras pessoas realizaram uma conexão semelhante com sistemas externos. Por exemplo: VMWare, MS SQL Server, MySQL, modems externos e assim por diante. Sua parte de servidor é implementada internamente. E é muito conveniente conectar-se sem nenhuma ajuda, mesmo por meio de um canal nomeado, ou via TCP/IP e outros canais de comunicação. E você pode até escolher, por exemplo, por meio de um canal nomeado, mas remotamente via TCP/IP com a ajuda do utilitário "Named Pipe TCP Proxy". Ou seja, os usuários não precisam criar nenhum dispositivo adicional, mas apenas escolher o aplicativo cliente mais adequado e imediatamente se conectar e trabalhar.
 
Yuri, você está claramente confuso. Os pipelines de servidor podem ser facilmente criados em outras linguagens. É apenas a WinAPI.

Leve em consideração que a MQL5 é um ambiente de aplicativo seguro, e claramente um ambiente de cliente, no qual não é razoável criar funções de servidor.

Não tenho certeza de que a funcionalidade do servidor foi declarada. A funcionalidade do cliente foi planejada e implementada.
 

Acho que criei o código para o gateway. Ainda não o testei. Vou baixar e instalar o MinGW e ver o que está errado.

#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");
        // Criar o primeiro subprocesso para copiar informações de canais nomeados
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // Execute-o
        server->Start();
        Thread::Sleep(250);
        // Se o cliente tiver travado
        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) 
        {
            // Criar dois canais nomeados
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // Aguardando uma conexão do cliente
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // Dependendo da ordem do subprocesso, copie os dados de um canal nomeado para outro.
          if (i == 0) {
            needclose = true;
            i++;
            // Criar outro subprocesso para copiar informações dos canais nomeados no contador
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // Iniciar o subprocesso
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // Manipulador de exceções para clientes descartados 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

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

MinGW instalado, configurado e anexado ao NetBeans.

A ideia de criar um gateway full-duplex a partir de dois canais de servidor e redirecionar informações para clientes de um canal para outro não funcionou. Se um subprocesso do servidor lê um canal e o segundo envia algo para ele, o full duplex não funciona (pelo menos no Windows XP), porque às vezes o subprocesso que lê do canal intercepta mensagens do subprocesso que grava no mesmo canal e retorna as informações de volta.

Se você remover um dos subprocessos, a transmissão será feita por simplex de cliente para cliente sem nenhum problema.

No entanto, nem tudo está perdido, pois há também um modo sobreposto, ou seja, quando não são criados dois, mas apenas um canal, e vários clientes se conectam a ele simultaneamente. Nesse caso, o servidor não precisa ler informações do canal o tempo todo, porque tudo se baseia em eventos. Ou seja, se algum cliente enviar informações para o canal, o servidor lê seu evento e extrai a mensagem transmitida de lá. E para redirecionar as informações recebidas para o segundo cliente, isso já é uma questão de técnica. Estou no processo de criar uma implementação desse tipo.

 

É isso aí. Eu desisti. Estou cansado de mexer no código C++ e até mesmo na API do Win. Não tanto de codificar, mas de vasculhar informações dispersas no MSDN para tentar entender como tudo deve funcionar. Como não tenho experiência, enviei todo esse material para o Service Work. Consulte Refazer o código C++ em um gateway full duplex bidirecional

Talvez alguém mais experiente possa lidar facilmente com essa tarefa? Não descarto que o motivo das falhas seja o fato de eu não ter conseguido descobrir as configurações dos canais nomeados. Ou seja, é possível que nessas mesmas configurações você precise escrever algo corretamente e tudo poderá funcionar. Até o momento, não consegui fazer nada além do modo simplex e iniciá-lo.

 

Decidi tentar fazer amizade entre o MQL e o AutoIt por meio de pipelines.

Em resumo, apenas um rake e em qualquer lugar :)

Bem, consegui transferir para o AutoIt com um pouco de sorte, apenas os primeiros 4 bytes tiveram que ser descartados, pois há algum "lixo". O que é esse "lixo"?

Em seguida, tentei transferir para o MQL, o que é ainda mais divertido - não aparece nada. Ou talvez eu não esteja organizando a transferência corretamente.... Talvez todo o problema esteja nesses 4 bytes?

O que você pode me dizer?

 
fyords:

Decidi tentar fazer amizade entre o MQL e o AutoIt por meio de pipelines.

Em resumo, apenas um rake e em qualquer lugar :)

Bem, consegui transferir para o AutoIt com um pouco de sorte, apenas os primeiros 4 bytes tiveram que ser descartados, pois há algum "lixo". O que é esse "lixo"?

Em seguida, tentei transferir para o MQL, o que é ainda mais divertido - não aparece nada. Ou talvez eu não esteja organizando a transferência corretamente.... Talvez todo o problema esteja nesses 4 bytes?

O que você pode me dizer?

Sho, você também?
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
Então, você também está lá dentro?

Não, estou bem aqui). Então, foi assim:

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| Função de início do programa de script|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- esperar pelo servidor 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");
//--- enviar mensagem de boas-vindas
   string msg=__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__);
   //Print(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) ;/Cria uma instância de um pipe nomeado
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;//Permite que um processo servidor de pipe nomeado aguarde a conexão de um processo cliente
ConsoleWrite(ReadMsg($hwnd_pipe)) ;//Gravação de dados no fluxo 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

Essa parte da transferência de MQL para AutoIt. Ela funciona da seguinte forma.

Com uma string de Func ReadMsg($hPipe)

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

Eu como os primeiros 4 bytes e tudo funciona.

Pergunta: o que esses primeiros 4 bytes contêm?

 
fyords:

Eu corro os primeiros 4 bytes e tudo funciona.

Pergunta: o que esses primeiros 4 bytes contêm?

Ao transmitir cadeias de caracteres, 4 bytes do tamanho da cadeia vêm primeiro.
 
Dima_S:
Renat, quando está planejado fazer pips no MT4?
Eles foram criados na última versão do MetaTrader 4.