文章 "使用命名管道与 MetaTrader 5 进行无 DLL 通信" - 页 3

 
Renat:
我认为,终端之间的通信问题应用比例很小。但与外部系统的通信则更为重要和适用。这就是安全通道开通的目的。

没有人反对这一点,我的意思是说,声明这一切都是为了什么。但问题在于如何实施。毕竟,外部系统不一定是用 C 语言编写的,也可以用不同的编程语言创建。而在许多编程语言中,只有作为客户端才能通过文件操作,通过命名通道 连接到终端。但我们选择的技术是客户端-服务器技术,即如果两个客户端之间没有桥梁-网关,它们就不会相遇。也就是说,要么提供客户机-客户机技术,要么提供网关。结果就像克雷洛夫老爷爷的寓言故事《狐狸和葡萄》一样:

虽然眼睛能看见

但眼睛看不见。

伊-克雷洛夫


有必要看看其他人是如何实现与外部系统的类似联系的。例如VMWare、MS SQL Server、MySQL、外部调制解调器等等。它们的服务器部分都是在内部实现的。即使通过命名通道,或通过 TCP/IP 和其他通信通道,也可以非常方便地加入,无需任何辅助工具。例如,您甚至可以选择通过指定通道,但借助 "Named Pipe TCP Proxy "工具通过 TCP/IP 进行远程连接。也就是说,用户无需创建任何额外的辅助工具,只需选择最合适的客户端应用程序,并立即连接和工作。
 
尤里,你显然是糊涂了。服务器管道可以用其他语言轻松创建。这只是 WinAPI。

考虑到 MQL5 是一个安全的应用程序环境,而且显然是一个客户端环境,在其中创建服务器功能是不合理的。

我不确定是否声明了服务器功能。客户端功能已计划并实施。
 

我想我为网关编写了代码。还没有测试。我会下载并安装 MinGW,看看有什么问题。

#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");
        // 创建第一个子进程,从命名通道复制信息
        Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
        // 运行它
        server->Start();
        Thread::Sleep(250);
        // 如果客户端崩溃
        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) 
        {
            // 创建两个命名通道
            pipeServer1 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe1", PipeDirection::InOut, numThreads);
            pipeServer2 = gcnew NamedPipeServerStream("\\\\.\\pipe\\testpipe2", PipeDirection::InOut, numThreads);
        }
                                
        threadId = Thread::CurrentThread->ManagedThreadId;


        // 等待来自客户端的连接
        pipeServer->WaitForConnection();

        Console::WriteLine("Client connected on thread.", threadId);
        try
        {  
          // 根据子进程的顺序,将数据从一个命名通道复制到另一个命名通道。
          if (i == 0) {
            needclose = true;
            i++;
            // 创建另一个子进程,将指定通道的信息复制到计数器上
            Thread server = gcnew Thread(gcnew ThreadStart(&ServerThread));
            // 启动子进程
            server->Start();
            pipeServer1->CopyToAsync(pipeServer2);
          } else {
            pipeServer2->CopyToAsync(pipeServer1);
          }
        }
        // 丢弃客户端的异常处理程序 
        catch (IOException^ e)
        {
            Console::WriteLine("ERROR: {0}", e->Message);
        }
        if (needclose) {
          pipeServer1->Close();
          pipeServer2->Close();
        }
     }
};

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

MinGW 已安装、配置并连接到 NetBeans。

从两个服务器通道创建一个全双工网关,并将客户信息从一个通道重定向到另一个通道的想法行不通。如果一个服务器子进程读取一个通道,而另一个子进程向它发送信息,全双工网关就无法工作(至少在 Windows XP 上是这样),因为有时从通道读取信息的子进程会拦截向同一通道写入信息的子进程的信息,并将信息返回。

如果删除其中一个子进程,就可以顺利地以单工方式从客户端传输到客户端。

不过,并非所有情况都是如此,因为还有一种重叠模式,即创建的通道不是两个,而是只有一个,多个客户端同时连接到该通道。在这种情况下,服务器不需要一直从通道中读取信息,因为一切都基于事件。也就是说,如果有客户端向通道发送信息,服务器就会读取其事件并从中提取传输的信息。而将接收到的信息重定向到第二个客户端--这已经是一个技术问题了。我正在创建这样一个实施方案。

 

就是这样。我放弃了。我已经厌倦了摆弄 C++ 代码甚至 Win API。与其说是编码,不如说是在 MSDN 上挖掘零散的信息碎片,试图理解一切应该如何工作。由于缺乏经验,我把这些东西都交给了服务工作。 参见将 C++ 代码重做为双向全双工网关

也许更有经验的人可以轻松完成这项任务?我不排除失败的原因是我不知道命名通道的设置。到目前为止,我除了在单工模式下启动外,什么也没做。

 

我决定尝试通过管道在 MQL 和 AutoIt 之间建立友好关系。

简而言之,只有一个耙子,而且无处不在:)

幸运的是,我成功地转入了 AutoIt,只丢弃了前 4 个字节,因为其中有一些 "垃圾"。这些 "垃圾 "是什么?

然后我试着转到 MQL,这里就更好玩了--什么都没有。也许是我没有正确组织传输....。也许问题就出在这 4 个字节上?

您能告诉我什么?

 
fyords:

我决定尝试通过管道在 MQL 和 AutoIt 之间建立友好关系。

简而言之,只有一个耙子,而且无处不在:)

幸运的是,我成功地转入了 AutoIt,只丢弃了前 4 个字节,因为其中有一些 "垃圾"。这些 "垃圾 "是什么?

然后我试着转到 MQL,这里就更好玩了--什么都没有。也许是我没有正确组织传输....。也许问题就出在这 4 个字节上?

你能告诉我什么?

翔,你呢
Клуб Телепатов - MQL4 форум
  • www.mql5.com
Клуб Телепатов - MQL4 форум
 
sergeev:
你也在里面

不,我就在这儿)是这样的

MQL5

#include <Files\FilePipe.mqh>

CFilePipe  ExtPipe;
//+------------------------------------------------------------------+
//| 脚本程序启动功能|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- 等待管道服务器
   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");
//--- 发送欢迎信息
   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) ;//创建已命名管道的实例
_NamedPipes_ConnectNamedPipe($hwnd_pipe) ;//让命名管道服务器进程等待客户进程连接
ConsoleWrite(ReadMsg($hwnd_pipe)) ;//将数据写入 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

这部分从 MQL 转到 AutoIt。它的工作原理是

使用来自 Func ReadMsg($hPipe) 的字符串

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

我吃掉了前 4 个字节,一切正常。

问题:这前 4 个字节包含什么内容?

 
fyords:

我吃掉了前 4 个字节,一切正常。

问题:这前 4 个字节包含什么内容?

传输字符串时,其大小的 4 个字节排在前面。
 
Dima_S:
雷纳特,计划何时在 MT4 中创建点数?
在 MetaTrader 4 的最后一个版本中已经有了。