English Русский 中文 Deutsch 日本語 Português
El Asesor Experto MetaTrader 4 intercambia información con el mundo exterior

El Asesor Experto MetaTrader 4 intercambia información con el mundo exterior

MetaTrader 4Ejemplos | 12 abril 2016, 14:08
1 599 0
more
[Eliminado]

Introducción

Esta es una herramienta de software que proporciona al Asesor Experto MetaTrader 4 la capacidad de crear tanto servidores como clientes. Los clientes pueden realizar conexiones tanto con sus propios servidores como con cualquier otro tipo de servidores que proporcionen un protocolo de conexión entre pares. La herramienta de software que se proporciona tiene dos componentes:

  • NetEventsProc.exe: es un procesador de Windows que funciona en segundo plano (sin consola) y se inicia (y se detiene) cuando se necesite por el segundo componente NetEventsProcDLL.dll. Por petición de las aplicaciones, se puede crear tanto para servidores como para clientes: ambos para sus propios servidores y para cualquier otro tipo de servidores que proporcione protocolo de conexión de pares. Por ejemplo, puede crear clientes que intercambien información en páginas web. Si puede soportar el protocolo HTTP, por supuesto.

  • NetEventsProcDLL.dll: es la interfaz entre la aplicación que necesita que el NetEventsProc.exe procese servicios y a sí mismo. Gracias a la interfaz DLL, cualquier programa escrito en cualquier lenguaje de programación puede utilizar esta herramienta de software para el intercambio de información en dos direcciones. El Asesor Experto MetaTrader 4 es sólo un ejemplo de un posible uso de esta herramienta.

Este artículo está estructurado de la siguiente manera:

  • Quick Start: el uso práctico de la herramienta de software que se proporciona, se demuestra primero en un ejemplo simple, luego en uno más complejo.

  • DLL Interface Specification: la descripción detallada de las funciones y servicios DLL están proporcionadas por NertEventsProc.exe cuando se dirige a estas funciones desde las aplicaciones.

  • Implementación del proyecto: los detalles de la implementación de este proyecto se clarifican cuando es posible.

El archivo NetServerClient.zip que se adjunta, contiene dos proyectos de Microsoft Visual Studio 2010 Ultimate: NetEventsProcs: para construir NetEventsProc.exe, y NetEventsProcDLL para construir NetEventsProcDLL.dll. Los códigos fuente están comentados en los detalles. Puede mirar los detalles de implemetación y personalizar el proyecto con sus necesidades específicas si quiere.

NetEventsProc.exe implementa el servidor y los clientes utilizando conectores asíncronos. Para cambiar los interruptores de los conectores al modo asíncrono, se utiliza uno de los métodos de funcionamiento en modo asíncrono: vincular los conectores a los eventos de red de WSAEventSelect(h_Socket, h_Event, FD_ALL_EVENTS).

Esto proyecto se basa en el trabajo fundamenta del gran Maestro Elmue.



1. Inicio rápido

1,1. El archivo exe.zip

Extraiga este archivo. Encontrará los siguientes componentes:

  • NetEventsProcDLL.dll: colóquelo en la carpeta "C:\Windows\System32\".

  • NetEventsProc.exe: cree la carpeta "C:\NetEventsProc\" y coloque este componente dentro de esa carpeta. NetEventsProcDLL.dll buscará el módulo NetEventsProc.exe exactamente en esta carpeta.

Los siguientes componentes de este archivo proporcionan un mecanismo de importación de funciones DLL desde NetEventsProcDLL.dll a las aplicaciones.

  • ImportNetEventsProcDLL.mqh: prototipos de las funciones importadas al Asesor Experto MetaTrader 4 desde NetEventsProcDLL.dll. Coloque este archivo en la carpeta de datos de la terminal "MetaTrader 4\experts\include\".

  • cNetEventsProcDLL.h: definición de clase C++ que contiene todos los proyectos de funciones DLL desde NetEventsProcDLL.dll. Incluir este programa de clase C++ permite importar todas las funciones DLL de NetEventsProcDLL.dll. Para los programas escritos en otros lenguajes de programación, debería o importar cada función por separado, o reescribir la definición de esta clase repetidamente.

  • NetEventsProcDLL.lib: módulo que se incluye en los programas que importan las funciones DLL desde NetEventsProcDLL.dll en módulo de vinculación de dinámica del tiempo de carta (recopilado con: /EHsc/link NetEventsProcDLL.lib).

En realidad, esto completa el proceso de configuración. Ahora puede escribir Asesores Expertos de MetaTrader 4 y aplicaciones en cualquier lenguaje de programación utilizando las funciones DLL para crear servidores y clientes.

Para no divagar, aquí ofrecemos los códigos fuente de ImportNetEventsProcDLL.mqh y cNetEventsProcDLL.h. El archivo de cabecera ImportNetEventsProcDLL.mqh contiene los prototipos de las funciones DLL importadas de NetEventsProcDLL.dll y dos funciones de servicio adicionales:

string GetErrMsg(int s32_Error);
string FormatIP(int IP);

La función GetErrMsg convierte los códigos de retorno del las funciones DLL en texto. La función FormatIP convierte la representación binaria de la dirección de IP en formato de texto estándar como "93.127.110.161". Debería colocar el archivo ImportNetEventsProcDLL.mqh en la carpeta de datos de la terminal "MetaTrader 4\experts\include\".

Aquí tiene el código fuente de ImportNetEventsProcDLL.mqh (sólo se ofrece una parte de este archivo que corresponde directamente con la definición de los prototipos de las funciones DLL importadas):

// ImportNetEventsProcDLL.mqh

#import "NetEventsProcDLL.dll"
// Only for Clients:
int ConnectTo(string  ps8_ServerIP,             // in - string ps8_ServerIP = "0123456789123456"
              int     s32_Port,                 // in 
              int&    h_Client[]);              // out - int h_Client[1]
                 
int ConnectClose(int h_Client);                 // in
//
// Only for Server:
int ServerOpen(int  s32_Port);                  // in

int GetAllConnections(int& ph_Client[],         // out - int ph_Client[62]
                      int& ps32_ClientIP[],     // out - int ps32_ClientIP[62]
                      int& ps32_ClientCount[]); // out - int ps32_ClientCount[1]
                       
int DisconnectClient(int h_Client);             // in

int ServerClose();
//
// For both: Clients and Server
int SendToInt   (int  h_Client,             // in
                 int& ps32_SendBuf[],       // in
                 int  s32_SendBufLen);      // in - SendBuf[] array size in int element 
                 
int SendToDouble(int     h_Client,          // in
                 double& pd_SendBuf[],      // in
                 int     s32_SendBufLen);   // in - SendBuf[] array size in double element 
                 
int SendToString(int    h_Client,           // in
                 string ps8_SendBuf,        // in
                 int    s32_SendBufLen);    // in - SendBuf string size in char element
                 

int ReadFromInt   (int h_Client,            // in
                   int& ps32_ReadBuf[],     // in 
                   int  s32_ReadBufLen,     // in  - ReadBuf[] array size in int element
                   int& ps32_ReadLen[]);    // out - int ps32_ReadLen[1] - count of actually read data in int element
                  
int ReadFromDouble(int     h_Client,        // in
                   double& pd_ReadBuf[],    // in
                   int     s32_ReadBufLen,  // in  - ReadBuf[] array size in double element
                   int&    ps32_ReadLen[]); // out - int ps32_ReadLen[1] - count of actually read data in double element
                   
int ReadFromString(int     h_Client,        // in
                   string  ps8_ReadBuf,     // in
                   int     s32_ReadBufLen,  // in  - ReadBuf   string size in char element
                   int&    ps32_ReadLen[]); // out - int ps32_ReadLen[1] - count of actually read data in char element
//                   
#import
//***************************************************************************************
...
...
...
// Get a human readable error message for an API error code
string GetErrMsg(int s32_Error)
{
   ...
   .. 
}

// Convert DWORD IP to string IP
string FormatIP(int IP)
{
   ...
   ...
   ...
}      

El archivo cNetEventsProcDLL.h tiene una definición de clase C++ con todas las funciones DLL importadas de NetEventsProcDLL.dll. Aquí tiene el código fuente de este archivo:

//+---------------------------------------------------------------------------+
//|                                            cNetEventsProcDLL.h            |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |

//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+

// cNetEventsProcDLL.h

#pragma once

#define EXPFUNC __declspec(dllexport)
        
class cNetEventsProcDLL
{
public:
    static BOOL MessageDLL_PROCESS_ATTACH(void);
    static BOOL MessageDLL_PROCESS_DETACH(void);
//*******************************************************************************************************************
    static EXPFUNC int __stdcall ConnectTo(char* ps8_ServerIP, //in - ps8_ServerIP = "0123456789123456"
                                           int   s32_Port,     //in 
                                           int*  ph_Client);   //out - int ph_Client[1]

    static EXPFUNC int __stdcall ConnectClose(int h_Client);   //in 

    static EXPFUNC int __stdcall ServerOpen(int s32_Port);     //in

    static EXPFUNC int __stdcall GetAllConnections(int* ph_Client,         // out - int ph_Client[62]
                                                   int* ps32_ClientIP,     // out - int ps32_ClientIP[62]
                                                   int* ps32_ClientCount); // out - int ps32_ClientCount[1]
    
    static EXPFUNC int __stdcall DisconnectClient(SOCKET h_Client);        // in 

    static EXPFUNC int __stdcall ServerClose();

    static EXPFUNC int __stdcall SendToInt(SOCKET h_Client,             // in
                                           int*   ps32_SendBuf,         // in
                                           int    s32_SendBufLen);      // in - SendBuf[] array size in int element

    static EXPFUNC int __stdcall SendToDouble(SOCKET  h_Client,         // in
                                              double* pd_SendBuf,       // in
                                              int     s32_SendBufLen);  // in - SendBuf[] array size in double element

    static EXPFUNC int __stdcall SendToString(SOCKET h_Client,          // in
                                              char*  ps8_SendBuf,       // in
                                              int    s32_SendBufLen);   // SendBuf string size in char element

    static EXPFUNC int __stdcall ReadFromInt(SOCKET h_Client,           // in
                                             int*   ps32_ReadBuf,       // in
                                             int    s32_ReadBufLen,     // ReadBuf[] array size in int element
                                             int*   ps32_ReadLen);      // out - int ps32_ReadLen[1] - actual count of read data in int element

    static EXPFUNC int __stdcall ReadFromDouble(SOCKET  h_Client,       // in
                                                double* pd_ReadBuf,     // in
                                                int     s32_ReadBufLen, // ReadBuf[] array size in double element
                                                int*    ps32_ReadLen);  // out - int ps32_ReadLen[1] - actual count of read data in double element

    static EXPFUNC int __stdcall ReadFromString(SOCKET h_Client,        // in
                                                char*  ps8_ReadBuf,     // in
                                                int    s32_ReadBufLen,  // ReadBuf[] array size in char element
                                                int*   ps32_ReadLen);   // out - int ps32_ReadLen[1] - actual count of read data in char element
//*******************************************************************************************************************
protected:
    static DWORD SendTo(SOCKET h_Client,   char* ps8_SendBuf, INT s32_SendBufLen);
    static DWORD ReadFrom(SOCKET h_Client, char* ps8_ReadBuf, INT s32_ReadBufLen, INT& s32_ReadLen);
};

1.2. El archivo FastStart.zip

Este archivo contiene los códigos fuente de todos los programas que se han utilizado en ejemplos demo. Los programas C++ están representados como los proyectos Client y EchoServer de Microsoft Visual Studio 2010 Ultimate. Los códigos fuente de los programas MQL4 también están presentes en este archivo, junto con el archivo ImportNetEventsProcDLL.mqh, utilizado para importar las funciones DLL a los programas MQL4. Coloque este archivo en la carpeta "MetaTrader 4\experts\include\".

Para diálogos futuros, los códigos fuente de todos estos programas se enumeran en el texto. Se considerarán tres ejemplos que demuestran el trabajo con todas las funciones DLL en MQL4 y lenguajes de programación C++:

  • La Sección 1.2.1 demuestra el intercambio de información entre el servidor del Asesor Experto de MetaTrader 4 y el cliente C++.

  • La Sección 1.2.2 demuestra el intercambio de información entre el servidor C++ y el cliente Asesor Experto MetaTrader 4.

  • La Sección 1.2.3 demuestra el intercambio de información entre los Asesores Expertos de MetaTrader 4. Uno de estos AEs actúa como servidor, proporcionando otros indicadores de Asesores Expertos de MetaTrader 4 (los clientes Asesores Expertos) con los valores del indicador. En otras palabras, se ha implementado la distribución de los valores de un indicador "seguro" para los clientes.

1.2.1 Los servidores de los Asesores Expertos de MetaTrader 4 y el programa de cliente C++

Considere esta tarea de intercambio de programación entre el Asesor Experto y los programas C++:

  • EchoServer.mq4: el Asesor Experto actúa en cada servidor eco.

  • Client.cpp: el programa C++ actúa como un cliente para este servidor de Asesor Experto.

El cliente C++ lee los mensajes que introduce el usuario en la consola y los envía al Asesor Experto. El Asesor Experto recibe los mensajes, los muestra en la ventana de la terminal y los envía de nuevo al receptor. Las siguientes imágenes ilustran esta idea:

Imagen 1. Los servidores de los Asesores Expertos de MetaTrader 4 y el programa de cliente C++

Aquí tiene el código fuente del Asesor Experto de MetaTrader 4, EchoServer.mq4, que actúa como un servidor eco.

//+---------------------------------------------------------------------------+
//|                                            EchoServer.mq4                 |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+
#property copyright "Copyright © 2012, https://www.mql4.com/ ru/users/more"
#property link      "https://www.mql4.com/ ru/users/more"
#include <ImportNetEventsProcDLL.mqh>
/*int ServerOpen(int  s32_Port); // in
*/
/*int ServerClose();
*/
/*int GetAllConnections(int& ph_Client[],         // out - int ph_Client[62]
                        int& ps32_ClientIP[],     // out - int ps32_ClientIP[62]
                        int& ps32_ClientCount[]); // out - int ps32_ClientCount[1]
*/                      
/*int SendToString(int    h_Client,               // in
                   string ps8_SendBuf,            // in
                   int    s32_SendBufLen);        // in - SendBuf string size in char element
*/ 
/*int ReadFromString(int     h_Client,            // in
                   string    ps8_ReadBuf,         // in
                   int       s32_ReadBufLen,      // in  - ReadBuf   string size in char element
                   int&      ps32_ReadLen[]);     // out - int ps32_ReadLen[1] - count of actually read data in char element     
*/                              
// Globals variables
int s32_Error;
int i;

int s32_Port = 2000;
bool b_ServerOpened = false;

// for GetAllConnections(ph_Client, ps32_ClientIP, ps32_ClientCount)
int ph_Client       [62];
int ps32_ClientIP   [62];
int ps32_ClientCount[1 ];


// for int ReadFromString(h_Client, ps8_Buf, s32_BufLen, ps32_ReadLen)
// for int SendToString  (h_Client, ps8_Buf, s32_BufLen)
string ps8_Buf = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
int    s32_BufLen;
int    ps32_ReadLen[1];
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
   //----
   s32_BufLen = StringLen(ps8_Buf);
   
   if (!b_ServerOpened)
   {
      s32_Error = ServerOpen(s32_Port);
      Print("ServerOpen() return is: ",GetErrMsg(s32_Error));
      
      if (s32_Error == OK)
      {
         b_ServerOpened = true;
         Print("Server is Opened and Waiting fo Client connection requests...");
      }
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   if (b_ServerOpened)
   {
      s32_Error = ServerClose();
      Print("ServerClose() return is: ",GetErrMsg(s32_Error));
      
      if (s32_Error == OK)
         b_ServerOpened = false;
   }
//----
   return(0);
  }  

int start()
{
//----
   if (!b_ServerOpened)
      return(0);
      
   s32_Error = GetAllConnections(ph_Client, ps32_ClientIP, ps32_ClientCount);
   
   if (s32_Error != 0)
   {
      Print("GetAllConnections(...) return is: ",GetErrMsg(s32_Error));
      return(1);
   }
   

   Print("ClientCount = ", ps32_ClientCount[0]);

   
   for (i = 0; i<ps32_ClientCount[0]; i++)
   {
      Print("h_Client = ", ph_Client[i], "      Client IP =  ", FormatIP(ps32_ClientIP[i])); 
       
      s32_Error = ReadFromString(ph_Client[i], ps8_Buf, s32_BufLen, ps32_ReadLen);
      
      Print("ReadFromString(",ph_Client[i],",...) return is: ", GetErrMsg(s32_Error));
      
      if (s32_Error == 0)
      {
         Print("ReadFromString(",ph_Client[i],",...) ps32_ReadLen = ",ps32_ReadLen[0]);
         
         if (ps32_ReadLen[0] > 0)
         {
            Print("ReadFromString(",ph_Client[i],",...) Read data is: ", StringSubstr(ps8_Buf,0,ps32_ReadLen[0]));
            
            s32_Error = SendToString(ph_Client[i], ps8_Buf, StringLen(StringSubstr(ps8_Buf,0,ps32_ReadLen[0])));
            
            Print("SendToString(", ph_Client[i],",...) return is: ",GetErrMsg(s32_Error));
         }
      }
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+

Y aquí está el código fuente del cliente Client.cpp: programa C++ que actúa como un cliente para el servidor del Asesor Experto:

//+---------------------------------------------------------------------------+
//|                                            Client.cpp                     |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+

// Client.cpp

#include <winsock2.h>
#pragma comment(lib, "ws2_32")
#include <iostream>
#pragma comment(lib, "NetEventsProcDLL") // NetEventsProcDLL.lib placed in ...\FastStart\Client\
#include  "cNetEventsProcDLL.h"

// LocalIp = 0x6401a8c0 -> 192.168.1.100
// Returns a list of all local IP's on this computer (multiple IP's if multiple network adapters)
DWORD GetLocalIPs(char s8_IpList[][20], int &s32_IpCount);

/* This is the simple Client.
   It connects to Echo Server, send your input to Echo Server and read Echo from Server.

   ATTENTION !!! If your want to connect to local Server do not use  "127.0.0.1" !!!ATTENTION !!! 
   You may get all your local IP's by means of GetLocalIPs(...) function, here is call example:
   // Local IP's list
        char s8_IpList[10][20];

        int s32_IpCount;
        DWORD u32_Err = GetLocalIPs(s8_IpList, s32_IpCount);

        if (u32_Err)
        {
                printf("Get local IP's error !, no local IP means no network available...");
                return 1;
        }

        printf("\nLocal IP's list:\n");

        for (int i = 0; i<s32_IpCount; i++)
                printf("\n%s\n",s8_IpList[i]);
        //
*/

// This is the Server we want to connect to...
#define SERVER_IP   "192.168.1.5"  //this is mine local IP's get by means of GetLocalIPs(...) function,
                                   // do not use so called loopback  "127.0.0.1" address !!! 
#define PORT         2000

int main()
{
        // Local IP's list
        char s8_IpList[10][20];

        int s32_IpCount;
        DWORD u32_Err = GetLocalIPs(s8_IpList, s32_IpCount);

        if (u32_Err)
        {
                printf("Get local IP's error !, no local IP means no network available...");
                return 1;
        }

        printf("\nLocal IP's list:\n");

        for (int i = 0; i<s32_IpCount; i++)
                printf("\n%s\n",s8_IpList[i]);
        //

        char s8_ServerIP[] = SERVER_IP;
        int  s32_Port      = PORT;
        int  ph_Client[1];

        int  h_Client;

        DWORD u32_Error = cNetEventsProcDLL::ConnectTo(SERVER_IP, PORT, ph_Client);

        if (u32_Error)
        {
                printf("\nConnectTo(...) failed with error: %d\n", u32_Error);
                return 1;
        }
        else
                printf("\nConnectTo(...) OK, ph_Client[0] = : %d\n", ph_Client[0]);

        h_Client = ph_Client[0];

        // Connection is established successfully ! Let's  have some SendTo(...) data on this connection...
        char  ps8_SendData[200];
        int   s32_SendDataLen;;

        char   ps8_ReadBuf[1025];
        DWORD  s32_ReadBufLen = 1025;
        int    ps32_ReadLen[1];

        while(true)
        {
                std::cout << "\nEnter something to send to Server or Exit 'q':\n" << std::endl;

                std::cin.getline(ps8_SendData, 200);

                s32_SendDataLen = strlen(ps8_SendData);

                OemToCharBuff(ps8_SendData, ps8_SendData, s32_SendDataLen);

                if (ps8_SendData[0] == 'q')
                {
                        u32_Error = cNetEventsProcDLL::ConnectClose(h_Client);
                        if (u32_Error)
                        {
                                printf("\nConnectClose(...) failed with error: %d\n", u32_Error);
                                break;
                        }
                        else
                        {
                                printf("\nConnectClose(...) OK.\n");
                                break;
                        }
                }

                u32_Error = cNetEventsProcDLL::SendToString(h_Client, ps8_SendData, s32_SendDataLen);   

                switch (u32_Error)
                {
                case 0:
                        printf("\nSendTo(...) OK");
                        printf("\nSendTo(%d...) sent %d bytes\n", h_Client, s32_SendDataLen);
                        CharToOemBuff(ps8_SendData, ps8_SendData, s32_SendDataLen);
                        printf("\nSendTo(%d...) Sent Data: %s\n",h_Client, ps8_SendData);
                        printf("Waiting now for Echo....");
                        break;
                case ERROR_INVALID_PARAMETER:
                        printf("\nSendTo(%d...) return is: ERROR_INVALID_PARAMETER(%d)\n",h_Client, u32_Error);
                        printf("\nERROR_INVALID_PARAMETER -> One of this parms or more: h_Client, ps8_SendData, u32_SendDataLen is invalid...\n");
                        break;
                case WSAEWOULDBLOCK:
                        printf("\nSendTo(%d...) return is: WSAEWOULDBLOCK(%d)\n",h_Client, u32_Error);
                        printf("\nWSAEWOULDBLOCK -> The data will be send after the next FD_WRITE event, do nouthing\n");
                        break;

                case WSA_IO_PENDING:
                        printf("\nSendTo(%d...) return is: WSA_IO_PENDING(%d)\n",h_Client, u32_Error);
                        printf("\nWSA_IO_PENDING -> Error: A previous Send operation is still pending. This data will not be sent, try latter\n");
                        break;

                default:
                        printf("\nSendTo(%d...)failed with severe error: %d\n",h_Client, u32_Error);
                        // Severe error -> abort event loop
                        printf("\nConnection was closed !\n");
                        break;
                };
                
                if (u32_Error == 0 || u32_Error == WSAEWOULDBLOCK)
                {
                        int ReadLen = 0;

                        while(!ReadLen)
                        {
                                u32_Error = cNetEventsProcDLL::ReadFromString(h_Client, ps8_ReadBuf, s32_ReadBufLen, ps32_ReadLen);

                                if (u32_Error)
                                {
                                        printf("\nReadFromString(%d...) failed with error: %d\n", h_Client, u32_Error);
                                        break;
                                }

                                ReadLen = ps32_ReadLen[0];
                        }
                        if (u32_Error)
                        {
                                printf("\nReadFromString(%d...) failed with error: %d\n", h_Client, u32_Error);
                        }
                        else
                        {
                                printf("\nReadFromString(%d...) OK, read %d  bytes\n", h_Client, ReadLen);
                        }
                                
                        if (ReadLen > 0)
                        {
                                CharToOemBuff(ps8_ReadBuf, ps8_ReadBuf, s32_SendDataLen);
                                ps8_ReadBuf[ReadLen] = 0;
                                printf("\nReadFromString(%d...) Read Data: %s\n", h_Client, ps8_ReadBuf);
                        }

                }

        }

        return 0;
}

// LocalIp = 0x6401a8c0 -> 192.168.1.100
// Returns a list of all local IP's on this computer (multiple IP's if multiple network adapters)
DWORD GetLocalIPs(char s8_IpList[][20], int &s32_IpCount)
{
        // Winsock version 2.0 is available on ALL Windows operating systems 
        // except Windows 95 which comes with Winsock 1.1
        WSADATA k_Data;
        DWORD u32_Error = WSAStartup(MAKEWORD(2,0), &k_Data);
        if (u32_Error)
                return u32_Error;

        int ps32_IpList[20];

        char s8_Host[500];
        if (gethostname(s8_Host, sizeof(s8_Host)) == SOCKET_ERROR)
                return WSAGetLastError();
        
        struct hostent* pk_Host = gethostbyname(s8_Host);
        if (!pk_Host)
                return WSAGetLastError();

        s32_IpCount = 0;

        for (DWORD i=0; TRUE; i++)
        {
                if (!pk_Host->h_addr_list[i])
                        break; // The IP list is zero terminated

                ps32_IpList[i] = *((DWORD*)pk_Host->h_addr_list[i]);

                s32_IpCount++;
        }

        if (!s32_IpCount)
                return WSAENETDOWN; // no local IP means no network available

        for (int i = 0; i<s32_IpCount; i++)
        {
                BYTE* pu8_Addr = (BYTE*)&ps32_IpList[i];
        
                sprintf(s8_IpList[i],"%d.%d.%d.%d",pu8_Addr[0], pu8_Addr[1], pu8_Addr[2], pu8_Addr[3]);
        }
        return 0;
}

Para iniciar este ejemplo demo, necesita:

  1. Colocar el archivo EchoServer.mq4 en la carpeta de datos del terminal "МetaТrader 4\experts\" y guárdelo.

  2. Abra el proyecto Client en Microsoft Visual Studio 2010 Ultimate y constrúyalo utilizando la configuración de Release. Si quiere construir el proyecto en otro IDE, no olvide especificar el módulo NetEventsProcDLL.lib como una entrada adicional para el editor (recopilado con: /EHsc/link NetEventsProcDLL.lib).

  3. Inicie el módulo ejecutable Client.exe. Recibirá un código de error 10057 y la lista de las IPs locales de su ordenador. Corrija la siguiente fila en el código fuente del Client.cpp

    #define SERVER_IP   "192.168.1.5"

    reemplazando "192.168.1.5" con la primera (o la única) IP local y recopile de nuevo el proyecto.

  4. Inicie el Asesor Experto EchoServer en cualquier gráfico en la terminal MetaTrader 4. Si todo se ha hecho correctamente, la ventana de la terminal mostrará el siguiente mensaje: "El retorno ServerOpen() es: OK", "El Servidor está abierto y esperando a las peticiones de conexión del Cliente...". A continuación, en cara tick, el Asesor Experto comprueba las peticiones de conexión, conecta y lee los mensajes entrantes de cada conexión, y envía una copia de los mensajes al receptor. El Asesor Experto muestra toda la información actual en la ventana de la terminal.

  5. Ahora puede iniciar el programa Client.exe construido en el paso 3.

  6. Puede iniciar varias copias de este programa y ver cómo intercambia la información el Asesor Experto con todas las copias.

  7. Si configura la IP global del ordenador en la que está funcionando el Asesor Experto, en lugar de IP local en el paso 3, puede iniciar Client.exe y comunicarse con el Asesor Experto en cualquier otro ordenador que esté conectado a Internet. Por supuesto, no olvide deshabilitar todas las protecciones de firewall.

1.2.2 Servidor del programa C++ y Cliente de Asesor Experto de MetaTrader 4

Ahora consideremos la tarea tradicional de intercambio de información entre el Asesor Experto de MetaTrader 4 y el programa C++:

  • EchoServer.mq4: el programa C++ actúa en cada servidor eco.

  • Client.mq4: el Asesor Experto actúa como cliente para este servidor C++.

El cliente de Asesor Experto lee las cotizaciones del símbolo en el que está funcionando y las envía al servidor C++. El servidor C++ devuelve las cotizaciones al receptor, que las recibe y las muestra en la ventana de la terminal. Las siguientes imágenes ilustran esta idea:

Imagen 2. Servidor del programa C++ y Cliente de Asesor Experto de MetaTrader 4

Aquí tiene el código fuente del Asesor Experto de MetaTrader 4 Client.mq4, que actúa como un cliente:

//+---------------------------------------------------------------------------+
//|                                            Client.mq4                     |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+
#property copyright "Copyright © 2012, https://www.mql4.com/ ru/users/more"
#property link      "https://www.mql4.com/ ru/users/more"
#include <ImportNetEventsProcDLL.mqh>
/*int ConnectTo(string  ps8_ServerIP,         // in - string ps8_ServerIP = "0123456789123456"
                int     s32_Port,             // in 
                int&    ph_Client[]);         // out - int ph_Client[1]
*/
/*int SendToDouble(int     h_Client,          // in
                   double& pd_SendBuf[],      // in
                   int     s32_SendBufLen);   // in - SendBuf[] array size in double element 
*/
/*int ReadFromDouble(int     h_Client,        // in
                     double& pd_ReadBuf[],    // in
                     int     s32_ReadBufLen,  // in  - ReadBuf[] array size in double element
                     int&    ps32_ReadLen[]); // out - int ps32_ReadLen[1] - count of actually read data in double element
*/                      
/*int ConnectClose(int h_Client);             // in
*/ 
       
// Globals variables
int s32_Error;
int i;
// for int ConnectTo(ps8_ServerIP, s32_Port, ph_Client); // out - int h_Client[1]
string ps8_ServerIP = "192.168.1.5";                     // mine local IP
int    s32_Port = 2000;
int    ph_Client[1];

bool b_ConnectTo = false;

// for int SendToDouble(ph_Client[0], pd_Buf, s32_BufLen);  
// for int ReadFromDouble(ph_Client[0], pd_Buf, s32_BufLen, ps32_ReadLen);
double pd_Buf[1];
int    s32_BufLen = 1;
int    ps32_ReadLen[1];
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----
   if (!b_ConnectTo)
   {
      s32_Error = ConnectTo(ps8_ServerIP, s32_Port, ph_Client);
      Print("ConnectTo(...) return is: ",GetErrMsg(s32_Error));
      Print("ConnectTo(...) handle is: ",ph_Client[0]);
      
      if (s32_Error == OK)
      {
         b_ConnectTo = true;
         Print("Client now is ConnectTo the Server: ",ps8_ServerIP);
      }
   }
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   if (b_ConnectTo)
   {
      s32_Error = ConnectClose(ph_Client[0]);
      Print("ConnectClose(...) return is: ",GetErrMsg(s32_Error));
      
      if (s32_Error == OK)
         b_ConnectTo = false;
   }
//----
   return(0);
}  

int start()
{
//----
   if (!b_ConnectTo)
      return(0);
   
   RefreshRates();
   
   double pd_Value[1];
   
   pd_Value[0] = NormalizeDouble(Bid,Digits);
      
   s32_Error = SendToDouble(ph_Client[0], pd_Value, s32_BufLen);
   
   
   if (s32_Error != 0)
   {
      Print("SendToDouble(",ph_Client[0],"...) return is: ",GetErrMsg(s32_Error));
      return(1);
   }
   else
      Print("SendToDouble(",ph_Client[0],"...) return is: OK");
      
   s32_Error = ReadFromDouble(ph_Client[0], pd_Buf, s32_BufLen, ps32_ReadLen);      
   
   if (s32_Error != 0)
   {
      Print("ReadFromDouble(",ph_Client[0],"...) return is: ", GetErrMsg(s32_Error));
      return(1);
   }
   else
      Print("ReadFromDouble(",ph_Client[0],"...) return is: OK"); 
   
   pd_Buf[0] = NormalizeDouble(pd_Buf[0],Digits);
   
   if (ps32_ReadLen[0] > 0)
      Print("Read doble value is: ", pd_Buf[0]);
   
//----
   return(0);
  }
//+------------------------------------------------------------------+

Y aquí está el código fuente del cliente del programa C++ EchoServer.cpp, que actúa como un servidor eco para el cliente del Asesor Experto:

//+---------------------------------------------------------------------------+
//|                                            EchoServer.cpp                 |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+

// EchoServer.cpp

#include <winsock2.h>
#pragma comment(lib, "NetEventsProcDLL") // NetEventsProcDLL.lib placed in ...\FastStart\EchoServer\ 
#include <iostream>
#include <conio.h>

#include  "cNetEventsProcDLL.h"

BOOL FormatIP(DWORD u32_IP, char* s8_IP);

int main()
{
        int s32_Port = 2000;
        
        // Try to create server listening on port 2000
        // You may change port.
        DWORD u32_Error = cNetEventsProcDLL::ServerOpen(s32_Port);

        if (u32_Error)
        {
                printf("\nServerOpen() failed with error: %d\n", u32_Error);
                return 1;
        }
        else
                printf("\nServerOpen() fine, we now are waiting for connections...\n");
        
        DWORD u32_Count = 0;
        DWORD u32_CountOld = 0;
        
        double pd_Buf[1025];
        DWORD  u32_BufLen = 1025;
        int    ps32_ReadLen[1];

        pd_Buf[0] = 0;

        int ph_Client[62];
        int ps32_ClientIP[62];
        int ps32_ClientCount[1];

        while(!kbhit())
        {
                u32_Error = cNetEventsProcDLL::GetAllConnections(ph_Client, ps32_ClientIP, ps32_ClientCount);
                
                if (u32_Error)
                {
                        printf("\nGetAllConnections(...) failed with error: %d\n", u32_Error);
                        break;
                }
                else
                        u32_Count = ps32_ClientCount[0];

                if (u32_Count != u32_CountOld)
                {
                        u32_CountOld = u32_Count;

                        printf("\nNumber of connections now = %d\n", u32_Count);
                        printf("#     h_Connect   (peer IP)\n");
                        
                        for (DWORD i = 0; i<u32_Count; i++)
                        {
                                char  s8_IP[20];
                                sprintf(s8_IP, "%s","123456789012345");

                                FormatIP(ps32_ClientIP[i], s8_IP);

                                printf("%d      %d       (%s)\n", i, ph_Client[i], s8_IP);
                        }
                }

                for (DWORD i = 0; i<u32_Count; i++)
                {
                        u32_Error = cNetEventsProcDLL::ReadFromDouble(ph_Client[i], pd_Buf, u32_BufLen, ps32_ReadLen);

                        if (u32_Error)
                        {
                                printf("ReadFromDouble(%d...) failed with error: %d\n", ph_Client[i], u32_Error);
                        }

                        if (ps32_ReadLen[0])
                        {
                                printf("ReadFromDouble(%d...) read %d double values\n", ph_Client[i], ps32_ReadLen[0]);
                                printf("\nReadFromDouble(%d...) Read Data: %9.5f\n", ph_Client[i], pd_Buf[0]);
                        }
                        
                        if (ps32_ReadLen[0])
                        {
                                u32_Error = cNetEventsProcDLL::SendToDouble(ph_Client[i], pd_Buf, ps32_ReadLen[0]);

                                if (u32_Error)
                                {
                                        printf("SendToDouble(%d...) failed with error: %d\n", ph_Client[i], u32_Error);
                                }
                                else
                                {
                                        printf("SendToDouble(%d...) sent %d double values\n", ph_Client[i], ps32_ReadLen[0]);
                                        printf("SendToDouble(%d...) sent Data: %9.5f\n",ph_Client[i], pd_Buf[0]);
                                }
                        }

                }
                
        }

        u32_Error = cNetEventsProcDLL::ServerClose();

        if (u32_Error)
        {
                printf("\nServerClose() failed with error: %d\n", u32_Error);
                return 1;
        }
        else
                printf("\nServerClose() fine...\n");

        Sleep(10000);
        return 0;
}

BOOL FormatIP(DWORD u32_IP, char* s8_IP)
{
        DWORD u32_Len = strlen(s8_IP);

        if ( u32_Len < 15)
                return FALSE;
        
        BYTE* pu8_Addr = (BYTE*)&u32_IP;
        sprintf(s8_IP,"%d.%d.%d.%d",pu8_Addr[0], pu8_Addr[1], pu8_Addr[2], pu8_Addr[3]);

        return TRUE;
}

Para iniciar este ejemplo demo, necesita:

  1. Colocar el archivo Client.mq4 en la carpeta de datos de la terminal "MetaTrader 4\experts\", y asignar la IP local (obtenida en los ejemplos anteriores 1.2.1) a la fila

    string ps8_ServerIP = "192.168.1.5";

    y recopilarlo. Si el servidor C++ se va a iniciar en otro ordenador, copie aquí la IP global de este ordenador. No se olvide de deshabilitar las protecciones de firewall.

  2. Abra el proyecto Client en Microsoft Visual Studio 2010 Ultimate y constrúyalo utilizando la configuración de Release. Si quiere construir el proyecto en otro IDE, no olvide especificar el módulo NetEventsProcDLL.lib como una entrada adicional para el editor (recopilado con: /EHsc/link NetEventsProcDLL.lib).

  3. Inicie el servidor C++ EchoServer.exe. Si todo se ha hecho correctamente, la consola mostrará el siguiente mensaje: "ServerOpen() correcto, estamos esperando las conexiones...". Al presionar cualquier tecla, se cerrará el servidor y finalizará el programa.

  4. Inicie el Client.mq4 en cualquier gráfico en la terminal MetaTrader 4.

  5. Puede iniciar el cliente simultáneamente en varios gráficos, en una o en varias terminales, en uno o varios ordenadores.

  6. Mire cómo funcionan el servidor C++ y los clientes MetaTrader 4. Pulse cualquier tecla en la consola del servidor C++, y el programa C++ cerrará el servidor y finalizará.

1.2.3 El indicador del Asesor Experto de MetaTrader 4 (el servidor del Asesor Experto) y el indicador de cliente de MetaTrader 4

El indicador del Asesor Experto (el servidor del Asesor Experto) proporciona los indicadores de Clientes con los valores del indicador. En este caso, estos son los valores del indicador estándar iEnvelops(...). Este ejemplo puede tener un valor práctico para la distribución de los valores del indicador "asegurado" a todos clientes suscritos.

Las siguientes imágenes ilustran esta idea:

Imagen 3. El indicador del Asesor Experto de MetaTrader 4 (el servidor del Asesor Experto) y el indicador de cliente de MetaTrader 4

Aquí tiene el código fuente del Asesor Experto de MetaTrader 4 ServerSendInd.mq4 , que actúa como proveedor de los valores del indicador iEnvelops(...):

//+---------------------------------------------------------------------------+
//|                                            ServerSendInd.mq4              |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+
#property copyright "Copyright © 2012, https://www.mql4.com/ ru/users/more"
#property link      "https://www.mql4.com/ ru/users/more"
#include <ImportNetEventsProcDLL.mqh>
/*int ServerOpen(int  s32_Port);                  // in
*/
/*int ServerClose();
*/
/*int GetAllConnections(int& ph_Client[],         // out - int ph_Client[62]
                        int& ps32_ClientIP[],     // out - int ps32_ClientIP[62]
                        int& ps32_ClientCount[]); // out - int ps32_ClientCount[1]
*/                      
/*int ReadFromString(int     h_Client,            // in
                   string    ps8_ReadBuf,         // in
                   int       s32_ReadBufLen,      // in  - ReadBuf   string size in char element
                   int&      ps32_ReadLen[]);     // out - int ps32_ReadLen[1] - count of actually read data in char element     
*/ 
/*int SendToDouble(int     h_Client,              // in
                   double& pd_SendBuf[],          // in
                   int     s32_SendBufLen);       // in - SendBuf[] array size in double element   
*/                                            
// Globals variables
int s32_Error;
int i;

int s32_Port = 2000;
bool b_ServerOpened = false;

// for GetAllConnections(ph_Client, ps32_ClientIP, ps32_ClientCount)
int ph_Client       [62];
int ps32_ClientIP   [62];
int ps32_ClientCount[1 ];

// for int ReadFromString(h_Client, ps8_ReadBuf, s32_ReadBufLen, ps32_ReadLen)
string ps8_ReadBuf = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
int    s32_ReadBufLen;
int    ps32_ReadLen[1];

// for int SendToDouble(ph_Client[0], pd_SendBuf, s32_SendBufLen);  
#define  BARS_COUNT  200
double pd_SendBuf      [BARS_COUNT];  //BARS_COUNT/2 Bars for each of 2 line 
int    s32_SendBufLen = BARS_COUNT;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
   //----
   s32_ReadBufLen = StringLen(ps8_ReadBuf);
   
   if (!b_ServerOpened)
   {
      s32_Error = ServerOpen(s32_Port);
      Print("ServerOpen() return is: ",GetErrMsg(s32_Error));
      
      if (s32_Error == OK)
      {
         b_ServerOpened = true;
         Print("Server is Opened and Waiting for Clients connection requests...");
      }
   }
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   if (b_ServerOpened)
   {
      s32_Error = ServerClose();
      Print("ServerClose() return is: ",GetErrMsg(s32_Error));
      
      if (s32_Error == OK)
         b_ServerOpened = false;
   }
//----
   return(0);
}  

int start()
{
//----
   if (!b_ServerOpened)
      return(0);
      
   s32_Error = GetAllConnections(ph_Client, ps32_ClientIP, ps32_ClientCount);
   
   if (s32_Error != 0)
   {
      Print("GetAllConnections(...) failed with error: ",GetErrMsg(s32_Error));
      return(1);
   }
   
   Print("ClientCount = ", ps32_ClientCount[0]);
   
   for (i = 0; i<ps32_ClientCount[0]; i++)
   {
      Print("h_Client = ", ph_Client[i], "      Client IP =  ", FormatIP(ps32_ClientIP[i]));
      
      s32_Error = ReadFromString(ph_Client[i], ps8_ReadBuf, s32_ReadBufLen, ps32_ReadLen); 
      
      if (s32_Error != 0)
      {
         Print("ReadFromString(",ph_Client[i],") failed with error: ", GetErrMsg(s32_Error));
         continue;
      }

      if (ps32_ReadLen[0] > 0)
      {
         // ps8_ReadBuf = "EURUSDMinuts"   i.e. "Symbol+Timeframe"
         string Sym       = StringSubstr(ps8_ReadBuf,0,6);
         int    TimeFrame = StrToInteger(StringSubstr(ps8_ReadBuf,6,ps32_ReadLen[0]-6));
      

         int k;                
         for (k = 0; k<BARS_COUNT/2; k++)
         {
            while(true)
            {
               double UpperLine_k = iEnvelopes(Sym, TimeFrame, 14, MODE_SMA, 0, PRICE_CLOSE, 0.1, MODE_UPPER, k);
               if (GetLastError() != 0)
                  continue;
               else
                  break;   
            }    
            while(true)
            {           
               double LowerLine_k = iEnvelopes(Sym, TimeFrame, 14, MODE_SMA, 0, PRICE_CLOSE, 0.1, MODE_LOWER, k);
               if (GetLastError() != 0)
                  continue;
               else
                  break;
            }
             
            pd_SendBuf[k]              = UpperLine_k;
            pd_SendBuf[k+BARS_COUNT/2] = LowerLine_k;
         }
         
         s32_Error = SendToDouble(ph_Client[i], pd_SendBuf, s32_SendBufLen); 
         if (s32_Error != 0)
         {
            Print("SendToDouble(",ph_Client[i],") failed with error: ", GetErrMsg(s32_Error));

            continue;
         }
      }  
   }
//----
   return(0);
}
//+------------------------------------------------------------------+

Y aquí está el código fuente del indicador de Cliente ClientIndicator.mq4 que coge los valores del indicador iEnvelops(...) del Asesor Experto ServerSendInd.mq4:

//+---------------------------------------------------------------------------+
//|                                            ClientIndicator.mq4            |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+
#property copyright "Copyright © 2012, https://www.mql4.com/ en/users/more"
#property link      "https://www.mql4.com/ ru/users/more"
#include <ImportNetEventsProcDLL.mqh>

/*int ConnectTo(string  ps8_ServerIP,         // in - string ps8_ServerIP = "0123456789123456"
                int     s32_Port,             // in 
                int&    ph_Client[]);         // out - int ph_Client[1]
*/
/*                      
/*int ConnectClose(int h_Client);             // in
*/
/*int SendToString(int    h_Client,           // in
                   string ps8_SendBuf,        // in
                   int    s32_SendBufLen);    // in - SendBuf string size in char element
*/
/*int ReadFromDouble(int     h_Client,        // in
                     double& pd_ReadBuf[],    // in
                     int     s32_ReadBufLen,  // in  - ReadBuf[] array size in double element
                     int&    ps32_ReadLen[]); // out - int ps32_ReadLen[1] - count of actually read data in double element
*/
// Globals variables
int s32_Error;
int i;
// for int ConnectTo(ps8_ServerIP, s32_Port, ph_Client);  // out - int h_Client[1]
string ps8_ServerIP = "192.168.1.5";                      // mine local IP
int    s32_Port = 2000;
int    ph_Client[1]; 

bool b_ConnectTo = false;

// for int SendToString  (h_Client, ps8_SendBuf, s32_SendBufLen)
string ps8_SendBuf = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
int    s32_SendBufLen;  
 
// for int ReadFromDouble(ph_Client[0], pd_ReadBuf, s32_ReadBufLen, ps32_ReadLen);
#define BARS_COUNT  200
double  pd_ReadBuf      [BARS_COUNT];
int     s32_ReadBufLen = BARS_COUNT;
int     ps32_ReadLen[1]; 
               
string Indicator_Name = "Envelopes: ";
//----
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red

double UpperLine[];
double LowerLine[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
   SetIndexStyle (0,DRAW_LINE);
   SetIndexBuffer(0,UpperLine);
   
   SetIndexStyle (1,DRAW_LINE);
   SetIndexBuffer(1,LowerLine);
   
   s32_SendBufLen = StringLen(ps8_SendBuf);
   
   if (!b_ConnectTo)
   {
      s32_Error = ConnectTo(ps8_ServerIP, s32_Port, ph_Client);
      Print("ConnectTo(...) return is: ",GetErrMsg(s32_Error));
      Print("ConnectTo(...) handle is: ",ph_Client[0]);
      
      if (s32_Error == OK)
      {
         b_ConnectTo = true;
         Print("Client now is ConnectTo the Server: ",ps8_ServerIP);
      }
   }
//----   
   return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
    //----
   if (b_ConnectTo)
   {
      s32_Error = ConnectClose(ph_Client[0]);
      Print("ConnectClose(...) return is: ",GetErrMsg(s32_Error));
      
      if (s32_Error == OK)
         b_ConnectTo = false;
   }
//----
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()                          
{
//----
   if (!b_ConnectTo)
      return(0);
      
    string Sym       = Symbol();
    int    TimeFrame = Period();
    ps8_SendBuf = Symbol() + DoubleToStr(Period(),0);
    
    s32_Error = SendToString(ph_Client[0], ps8_SendBuf, StringLen(ps8_SendBuf));
    
    if (s32_Error != 0) 
    {       
      Print("SendToString(", ph_Client[0],",...) failed with error: ",GetErrMsg(s32_Error));
      return (1);
    }
    
    s32_Error = ReadFromDouble(ph_Client[0], pd_ReadBuf, s32_ReadBufLen, ps32_ReadLen);      
   
   if (s32_Error != 0)
   {
      Print("ReadFromDouble(",ph_Client[0],"...) return is: ", GetErrMsg(s32_Error));
      return(1);
   }
   
   if (ps32_ReadLen[0] == 0)
      return (0);
 
//--------------------------------------------------------------------
    int Counted_bars = IndicatorCounted();       // Number of calculated bars 
    i = Bars - Counted_bars - 1;                 // Index of first not-calculated
    if (i > BARS_COUNT/2-1)  i = BARS_COUNT/2-1; // Calculate specified count if there are many bars
//-----------------------------------------------------------------------  
    for (i = BARS_COUNT/2-1; i >= 0; i--)
    {
         UpperLine  [i] = pd_ReadBuf[i];
         LowerLine  [i] = pd_ReadBuf[i+BARS_COUNT/2];
    }  
    
    return;                          
} // end of int start()
//--------------------------------------------------------------------

Para iniciar este ejemplo demo, necesita:

  1. Colocar el archivo ServerSendInd.mq4 en la carpeta de datos del terminal "МetaТrader 4\experts\" y recopilarlo.

  2. Colocar el archivo ClientIndicator.mq4 en la carpeta de datos de la terminal "MetaTrader 4\experts\", y asignar la IP local (obtenida en los ejemplos anteriores 1.2.1) a la fila:

    string ps8_ServerIP = "192.168.1.5";

    Si el servidor ServerSendInd se va a iniciar en otro ordenador, copie aquí la IP global de este ordenador. No se olvide de deshabilitar las protecciones de firewall. Recopílelo.

  3. Inicie ServerSendInd. Si todo se ha hecho correctamente, la consola mostrará el siguiente mensaje: "ServerOpen() correcto, estamos esperando las conexiones...".

  4. En cualquier gráfico de la terminal de MetaTrader 4, inicie el indicador ClientIndicator.mq4. Aparecerán dos líneas de indicadores en el gráfico. Si inicia el indicador estándar Envelops en el mismo gráfico, asegúrese de que ambas líneas de su indicador coinciden con las líneas del indicador estándar.

  5. Puede iniciar el indicador ClientIndicator simultáneamente en varios gráficos, en una o en varias terminales, en uno o varios ordenadores.

  6. Observe cómo funcionan el servidor ServerSendInd y ClientIndicator. Intente cambiar el periodo de tiempo del gráfico con el indicador ClientIndicator. El servidor ServerSendInd se configurará inmediatamente para enviar los valores del indicador de este periodo de tiempo.


2. Especificaciones de la interfaz DLL

En esta sección se describirá con detalle todas las funciones DLL y los parámetros que se necesitan para llamarlas. Todas as funciones vuelven a cero si se han ejecutado con éxito. De lo contrario, las funciones vuelven winsock2 API error codes. Todas las funciones DLL exportadas se proporcionan en la declaración de clase C++ cNetEventsProcDLL.h, por lo tanto se proporcionará el código fuente de este archivo:

//+---------------------------------------------------------------------------+
//|                                            cNetEventsProcDLL.h            |
//|                      Copyright © 2012, https://www.mql4.com/ en/users/more  |
//|                                       tradertobe@gmail.com                |
//+---------------------------------------------------------------------------+
//--- cNetEventsProcDLL.h
#pragma once
#define EXPFUNC __declspec(dllexport)
//---   
class cNetEventsProcDLL
  {
public:
   static BOOL MessageDLL_PROCESS_ATTACH(void);
   static BOOL MessageDLL_PROCESS_DETACH(void);
//---
   static EXPFUNC int __stdcall ConnectTo(char *ps8_ServerIP,             // in - ps8_ServerIP = "0123456789123456"
                                          int   s32_Port,                 // in 
                                          int*  ph_Client);               // out - int ph_Client[1]
//---
   static EXPFUNC int __stdcall ConnectClose(int h_Client);               // in 
//---
   static EXPFUNC int __stdcall ServerOpen(int s32_Port);                 // in
//---
   static EXPFUNC int __stdcall GetAllConnections(int* ph_Client,         // out - int ph_Client[62]
                                                  int* ps32_ClientIP,     // out - int ps32_ClientIP[62]
                                                  int* ps32_ClientCount); // out - int ps32_ClientCount[1]
//---
   static EXPFUNC int __stdcall DisconnectClient(SOCKET h_Client);        // in 
//---
   static EXPFUNC int __stdcall ServerClose();
//---
   static EXPFUNC int __stdcall SendToInt(SOCKET h_Client,             // in
                                          int   *ps32_SendBuf,         // in
                                          int    s32_SendBufLen);      // in -  SendBuf[] array size in int element
//---
   static EXPFUNC int __stdcall SendToDouble(SOCKET  h_Client,         // in
                                             double* pd_SendBuf,       // in
                                             int     s32_SendBufLen);  // in -  SendBuf[] array size in double element
//---
   static EXPFUNC int __stdcall SendToString(SOCKET h_Client,          // in
                                             char*  ps8_SendBuf,       // in
                                             INT   s32_SendBufLen);    // SendBuf string size in char element
//---
   static EXPFUNC int __stdcall ReadFromInt(SOCKET h_Client,           // in
                                            int   *ps32_ReadBuf,       // in
                                            int    s32_ReadBufLen,     // ReadBuf[] array size in int element
                                            int   *ps32_ReadLen);      // out - int ps32_ReadLen[1] - actual count of read data in int element
//---
   static EXPFUNC int __stdcall ReadFromDouble(SOCKET  h_Client,       // in
                                               double *pd_ReadBuf,     // in
                                               int     s32_ReadBufLen, // ReadBuf[] array size in double element
                                               int    *ps32_ReadLen);  // out - int ps32_ReadLen[1] - actual count of read data in double element
//---
   static EXPFUNC int __stdcall ReadFromString(SOCKET h_Client,        // in
                                               char  *ps8_ReadBuf,     // in
                                               int    s32_ReadBufLen,  // ReadBuf[] array size in char element
                                               int*   ps32_ReadLen);   // out - int ps32_ReadLen[1] - actual count of read data in char element
//---
protected:
   static DWORD SendTo(SOCKET h_Client,char *ps8_SendBuf,INT s32_SendBufLen);
   static DWORD ReadFrom(SOCKET h_Client,char *ps8_ReadBuf,INT s32_ReadBufLen,INT &s32_ReadLen);
  };

Ahora consideremos todas las funciones DLL para que aparezcan en este archivo:

  1. ConnectTo: petición al servidor de crear una conexión:

    static EXPFUNC int __stdcall ConnectTo(char* ps8_ServerIP, // in - ps8_ServerIP = "0123456789123456"
                                           int   s32_Port,     // in 
                                           int*  ph_Client);   // out - int ph_Client[1]

    Parámetros de la función:

    • char* ps8_ServerIP: dirección IP del servidor que quiere conectar (por ejemplo, "93.127.110.162"). Si el servidor es local, especifique la IP, no "127.0.01", sino la IP obtenida como se describe en el ejemplo 2.1.1.

    • int s32_Port: número del puerto al que "escucha" el servidor.

    • int* ph_Client: el control de la conexión está colocada en esta variable, si la función ha finalizado con éxito. Este control se debe utilizar en todas las siguientes operaciones de esta conexión.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    DWORD u32_Error = cNetEventsProcDLL::ConnectTo(SERVER_IP, PORT, ph_Client);
    
    if (u32_Error)
    {
            printf("\nConnectTo(...) failed with error: %d\n", u32_Error);
            return 1;
    }
    else
            printf("\nConnectTo(...) OK, ph_Client[0] = : %d\n", ph_Client[0]);
    
    int h_Client = ph_Client[0];
  2. ConnectClose: petición al servidor de crear una conexión:

    static EXPFUNC int __stdcall ConnectClose(int h_Client); // in 

    Parámetros de la función:

    • int h_Client: control de la conexión que debe estar cerrado. Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API.

    Ejemplo C++:

    int u32_Error = cNetEventsProcDLL::ConnectClose(h_Client);
    
        if (u32_Error)
                printf("\nConnectClose(...) failed with error: %d\n", u32_Error);
        else
                printf("\nConnectClose(...) OK.\n");
  3. ServerOpen: petición para crear el servidor.

    static EXPFUNC int __stdcall ServerOpen(int s32_Port); //in

    Parámetros de la función:

    • int s32_Port: número del puerto al que el servidor "escucha"esperando a las peticiones de los clientes. Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API.

    Ejemplo C++:

    int u32_Error = cNetEventsProcDLL::ServerOpen(s32_Port);
    
    if (u32_Error)
    {
            printf("\nServerOpen() failed with error: %d\n", u32_Error);
            return 1;
    }
    else
            printf("\nServerOpen() fine, we now are waiting for connections...\n");
  4. GetAllConnections: petición al servidor de recoger información sobre las conexiones actuales.

    static EXPFUNC int __stdcall GetAllConnections(int* ph_Client,         // out - int ph_Client[62]
                                                   int* ps32_ClientIP,     // out - int ps32_ClientIP[62]
                                                   int* ps32_ClientCount); // out - int ps32_ClientCount[1]

    Parámetros de la función:

    • int ph_Client[62]: gama de salida en la que el servidor coloca el control de todas las conexiones actuales.

    • int ph_Client[62]: gama de salida en la que el servidor coloca la dirección de IP de todas las conexiones actuales. Para convertir estas direcciones a formato estándar como "92.127.110.161", utilice la función de la fila FormatIP(int IP) para el Asesor Experto de MetaTrader 4 o cualquier función parecida que se dan en los ejemplos de los programas C++. El número 62 en el tamaño de las gamas se especifica sin coincidencia: designa el límite del número posible de conexiones (clientes) por un servidor.

    • int* ps32_ClientCount: el servidor coloca el número de las conexiones actuales en esta variable, es decir, el número de elementos en las gamas mencionadas anteriormente.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    int ph_Client[62];
    int ps32_ClientIP[62];
    int ps32_ClientCount[1];
    
    int u32_Error = cNetEventsProcDLL::GetAllConnections(ph_Client, ps32_ClientIP, ps32_ClientCount);
                    
    if (u32_Error)
    {
        printf("\nGetAllConnections(...) failed with error: %d\n", u32_Error);
    }
    else
       int u32_Count = ps32_ClientCount[0];
  5. DisconnectClient: petición al servidor de cerrar la conexión con uno de sus clientes.

    static EXPFUNC int __stdcall DisconnectClient(int h_Client); // in 

    Parámetros de la función:

    • int h_Client: control de la conexión que debe estar cerrado. Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API.

    Ejemplo C++:

    int u32_Error = cNetEventsProcDLL::DisconnectClient(h_Client);
    
    if (u32_Error)
            printf("\nDisconnectClient(...) failed with error: %d\n", u32_Error);
    else
            printf("\nDisconnectClient(...) OK.\n");
  6. ServerClose: petición para cerrar el servidor.

    static EXPFUNC int __stdcall ServerClose(); 

    Cuando se cierra el servidor, todas las conexiones actuales se cerrarán para que cada cliente consiga el código de retorno de "sin conexión" como respuesta de cualquier operación. Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    int u32_Error = cNetEventsProcDLL::ServerClose();
    
    if (u32_Error)
            printf("\nServerClose() failed with error: %d\n", u32_Error);
    else
            printf("\nServerClose() OK.\n");
  7. El siguiente grupo de funciones corresponde directamente al intercambio de datos a través de la conexión actual. La recepción de datos de cada conexión actual se realiza en el modo asíncrono, es decir, sin respuesta del receptor.

    Todos los datos enviados y recibidos en forma de unidad independiente de intercambio, es decir, bloque. Todos los bloques para cada receptor se acumulan en la pila FIFO. El receptor puede recuperar esos bloques de la pila en cualquier momento. Cada función de intercambio funciona con un solo bloque.

    Para las operaciones de envío de datos, es posible que esa función tenga éxito, pero el código de retorno es diferente a cero y puede tener los siguientes valores:

    • WSAEWOULDBLOCK: la operación tuvo éxito, los datos aún no se han enviado al receptor, pero se enviarán en el momento oportuno. No se requiere ninguna acción del usuario.

    • WSA_IO_PENDING: el envío de datos anterior aún no se ha completado, el usuario debe intentar enviar los datos más tarde. Esta situación es normal, por lo que se considera que la función se ha realizado con éxito.

    Cualquier otro código de retorno indica un error del usuario.

  8. SendToInt: petición para enviar un bloque de datos (gama de tipo int) a través de la conexión actual.

    static EXPFUNC int __stdcall SendToInt(SOCKET h_Client,        // in
                                           int*   ps32_SendBuf,    // in
                                           int    s32_SendBufLen); // in - SendBuf[] array size in int element

    Parámetros de la función:

    • SOCKET h_Client: control de la conexión actual.

    • int ps32_SendBuf[s32_SendBufLen]: un sólo bloque (gama tipo int) que necesita enviar al cliente.

    • int s32_SendBufLen: tamaño de la gama.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    int ps32_SendBuf[200];
    int s32_SendBufLen=200;
    
    int u32_Error = cNetEventsProcDLL::SendToInt(h_Client, ps32_SendBuf, s32_SendBufLen);   
    
    switch (u32_Error)
    {
       case 0:
           printf("\nSendTo(...) OK");
           break;
       case WSAEWOULDBLOCK:
           printf("\nSendTo(%d...) return is: WSAEWOULDBLOCK(%d)\n",h_Client, u32_Error);
           printf("\nWSAEWOULDBLOCK -> The data will be send after the next FD_WRITE event, do nouthing\n");
           break;
       case WSA_IO_PENDING:
           printf("\nSendTo(%d...) return is: WSA_IO_PENDING(%d)\n",h_Client, u32_Error);
           printf("\nWSA_IO_PENDING -> Error: A previous Send operation is still pending. This data will not be sent, try latter\n");
           break;
    
       default:
           printf("\nSendTo(%d...)failed with severe error: %d\n",h_Client, u32_Error);
           break;
    };
  9. SendToDouble: petición para enviar un bloque de datos (gama de tipo doble) a través de la conexión actual.

    static EXPFUNC int __stdcall SendToDouble(SOCKET h_Client,          // in
                                              double*  pd_SendBuf,      // in
                                              int      s32_SendBufLen); // in - SendBuf[] array size in int element

    Parámetros de la función:

    • SOCKET h_Client: control de la conexión actual.

    • double pd_SendBuf[s32_SendBufLen]: un sólo bloque (gama tipo doble) que necesita enviar al cliente.

    • int s32_SendBufLen: tamaño de la gama.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    double pd_SendBuf[200];
    int    s32_SendBufLen=200;
    
    int u32_Error = cNetEventsProcDLL::SendToDouble(h_Client, pd_SendBuf, s32_SendBufLen);   
    
    switch (u32_Error)
    {
       case 0:
           printf("\nSendTo(...) OK");
           break;
       case WSAEWOULDBLOCK:
           printf("\nSendTo(%d...) return is: WSAEWOULDBLOCK(%d)\n",h_Client, u32_Error);
           printf("\nWSAEWOULDBLOCK -> The data will be send after the next FD_WRITE event, do nouthing\n");
           break;
       case WSA_IO_PENDING:
           printf("\nSendTo(%d...) return is: WSA_IO_PENDING(%d)\n",h_Client, u32_Error);
           printf("\nWSA_IO_PENDING -> Error: A previous Send operation is still pending. This data will not be sent, try latter\n");
           break;
    
       default:
           printf("\nSendTo(%d...)failed with severe error: %d\n",h_Client, u32_Error);
           break;
    };
  10. SendToString: petición para enviar un bloque de datos (gama de tipo char) a través de la conexión actual.

    static EXPFUNC int __stdcall SendToString(SOCKET h_Client,        // in
                                              char*  ps8_SendBuf,     // in
                                              int    s32_SendBufLen); // in -  SendBuf[] array size in int element

    Parámetros de la función:

    • SOCKET h_Client: control de la conexión actual.

    • char ps8_SendBuf[s32_SendBufLen]: un sólo bloque (gama tipo char) que necesita enviar al cliente.

    • int s32_SendBufLen: tamaño de la gama.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    char ps8_SendBuf[200];
    int  s32_SendBufLen=200;
    
    int u32_Error = cNetEventsProcDLL::SendToString(h_Client, ps8_SendBuf, s32_SendBufLen);   
    
    switch (u32_Error)
    {
       case 0:
           printf("\nSendTo(...) OK");
           break;
       case WSAEWOULDBLOCK:
           printf("\nSendTo(%d...) return is: WSAEWOULDBLOCK(%d)\n",h_Client, u32_Error);
           printf("\nWSAEWOULDBLOCK -> The data will be send after the next FD_WRITE event, do nouthing\n");
           break;
       case WSA_IO_PENDING:
           printf("\nSendTo(%d...) return is: WSA_IO_PENDING(%d)\n",h_Client, u32_Error);
           printf("\nWSA_IO_PENDING -> Error: A previous Send operation is still pending. This data will not be sent, try latter\n");
           break;
    
       default:
           printf("\nSendTo(%d...)failed with severe error: %d\n",h_Client, u32_Error);
           break;
    };
  11. ReadFromInt: petición para recibir un bloque de datos (gama de tipo int) a través de la conexión actual.

    static EXPFUNC int __stdcall ReadFromInt(SOCKET h_Client,       // in
                                             int*   ps32_ReadBuf,   // in
                                             int    s32_ReadBufLen, // ReadBuf[] array size in int element
                                             int*   ps32_ReadLen);  // out - int ps32_ReadLen[1] - actual count of read data in int element

    Parámetros de la función:

    • SOCKET h_Client: control de la conexión actual.

    • int ps32_ReadBuf[s32_ReadBufLen]: gama de tipo int para recibir un bloque de datos.

    • int s32_ReadBufLen: tamaño de la gama receptora.

    • int* ps32ReadLen: esta variable mantiene el tamaño real del bloque de datos que se recibió y colocó en la gama ps32_ReadBuf[]. Si el tamaño de la gama receptora no es suficiente para recibir un bloque de datos, esta variable mantendrá el tamaño requerido para recibir un bloque de datos, con un signo negativo. El bloque se queda en la pila, y luego el código de retorno será igual a cero. Si no hay datos en la pila del cliente con un control específico, esta variable será igual a cero y el código de retorno será también igual a cero.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    int ps32_ReadBuf[2000];
    int s32_ReadBufLen=2000;
    int ps32_ReadLen[1];
    int u32_Error = cNetEventsProcDLL::ReadFromInt(h_Client, ps32_ReadBuf, s32_ReadBufLen, ps32_ReadLen);   
            
    if(u32_Error)
        printf("ReadFromInt(%d...) failed with error: %d", h_Client, u32_Error);
    else
        if(ps32_ReadLen[0] >= 0) 
            printf("ReadFromInt(%d...) fine, %d int number was read", h_Client, ps32_ReadLen[0]);
        else 
            printf("ReadFromInt(%d...) fine, but ReadBuf must be at least %d int number size", h_Client, -ps32_ReadLen[0]);
  12. ReadFromDouble: petición para recibir un bloque de datos (gama de tipo doble) a través de la conexión actual.

    static EXPFUNC int __stdcall ReadFromDouble(SOCKET h_Client,        // in
                                                double* pd_ReadBuf,     // in
                                                int     s32_ReadBufLen, // ReadBuf[] array size in double element
                                                int*    ps32_ReadLen);  // out - int ps32_ReadLen[1] - actual count of read data in double element

    Parámetros de la función:

    • SOCKET h_Client: control de la conexión actual.

    • double pd_ReadBuf[s32_ReadBufLen]: gama de tipo doble para recibir un bloque de datos.

    • int s32_ReadBufLen: tamaño de la gama receptora.

    • int* ps32ReadLen: esta variable mantiene el tamaño real del bloque de datos que se recibió y colocó en la gama ps32_ReadBuf[]. Si el tamaño de la gama receptora no es suficiente para recibir un bloque de datos, esta variable mantendrá el tamaño requerido para recibir un bloque de datos, con un signo negativo. El bloque se queda en la pila, y luego el código de retorno será igual a cero. Si no hay datos en la pila del cliente con un control específico, esta variable será igual a cero y el código de retorno será también igual a cero.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    double ps32_ReadBuf[2000];
    int    s32_ReadBufLen = 2000;
    int    ps32_ReadLen[1];
    int    u32_Error = cNetEventsProcDLL::ReadFromDouble(h_Client, pd_ReadBuf, s32_ReadBufLen, ps32_ReadLen);   
            
    if(u32_Error)
        printf("ReadFromDouble(%d...) failed with error: %d", h_Client, u32_Error);
    else
        if(ps32_ReadLen[0] >= 0) 
            printf("ReadFromDouble(%d...) fine, %d double number was read", h_Client, ps32_ReadLen[0]);
        else 
            printf("ReadFromDouble(%d...) fine, but ReadBuf must be at least %d double number size", h_Client, -ps32_ReadLen[0]);
  13. ReadFromString: petición para recibir un bloque de datos (gama de tipo char) a través de la conexión actual.

    static EXPFUNC int __stdcall ReadFromString(SOCKET h_Client,       // in
                                                char*  ps8_ReadBuf,    // in
                                                int    s32_ReadBufLen, // ReadBuf[] array size in char element
                                                int*   ps32_ReadLen);  // out - int ps32_ReadLen[1] - actual count of read data in char element

    Parámetros de la función:

    • SOCKET h_Client: control de la conexión actual.

    • char ps8_ReadBuf[s32_ReadBufLen]: gama de tipo char para recibir un bloque de datos.

    • int s32_ReadBufLen: tamaño de la gama receptora.

    • int* ps32ReadLen: esta variable mantiene el tamaño real del bloque de datos que se recibió y colocó en la gama ps32_ReadBuf[]. Si el tamaño de la gama receptora no es suficiente para recibir un bloque de datos, esta variable mantendrá el tamaño requerido para recibir un bloque de datos, con un signo negativo. El bloque se queda en la pila, y luego el código de retorno será igual a cero. Si no hay datos en la pila del cliente con un control específico, esta variable será igual a cero y el código de retorno será también igual a cero.

    Si tienen éxito, la función devuelve true, de otro modo, devolverá un código de error winsock2 API. Ejemplo C++:

    char ps8_ReadBuf[2000];
    int  s32_ReadBufLen = 2000;
    int  ps32_ReadLen[1];
    int  u32_Error = cNetEventsProcDLL::ReadFromString(h_Client, ps8_ReadBuf, s32_ReadBufLen, ps32_ReadLen);   
            
    if(u32_Error)
        printf("ReadFromStrung(%d...) failed with error: %d", h_Client, u32_Error);
    else
        if(ps32_ReadLen[0] >= 0)
            printf("ReadFromString(%d...) fine, %d char was read", h_Client, ps32_ReadLen[0]);
        else 
            printf("ReadFromString(%d...) fine, but ReadBuf must be at least %d char size", h_Client, -ps32_ReadLen[0]);

3. Implementación del proyecto

El archivo NetServerClient.zip que se adjunta, contiene dos proyectos de Microsoft Visual Studio 2010 Ultimate:

  • NetEventsProc: para construir NetEventsProc.exe.
  • NetEventsProcDLL: para construir NetEventsProcDLL.dll.

Los códigos fuente están comentados en los detalles. Puede mirar los detalles de implemetación y personalizar el proyecto con sus necesidades específicas si quiere.

NetEventsProc.exe implementa el servidor y los clientes utilizando conectores asíncronos. Para cambiar los interruptores de los conectores al modo asíncrono, se utiliza uno de los métodos de funcionamiento en modo asíncrono: vincular los conectores a los eventos de red de WSAEventSelect(h_Socket, h_Event, FD_ALL_EVENTS).

Si este artículo provoca el interés de los lectores, en la siguiente versión del mismo se discutirán todos los detalles de la implementación. Pero de momento, esto es todo. Tenga en cuenta de nuevo que este proyecto se basa en el trabajo fundamenta del gran Maestro Elmue.



4. Conclusión

Espero que este artículo resuelva el problema del intercambio de información entre la terminal de MetaTrader 4 y aplicaciones de una tercera parte, sin importar su ubicación: ya sea en un ordenador local o ajeno en relación a la terminal instalada. Espero que este artículo no tenga muchos códigos Spaghetti, y el proceso de utilización de las funciones DLL sea lo bastante simple y claro. Al menos, he intentado que sea así.

Habría que tener en cuenta un momento importante más:

Casi todos los ordenadores son nodos de una red de área local (del inglés local área network (LAN)). Incluso si sólo tiene un ordenador, es muy probable que el node de LAN consista en un ordenador.

La conexión a una red de amplio alcance (en inglés, wide área network (WAN)) se realiza a través de un dispositivo hardware adicional que se puede llamar router, módem o algún otro término técnico. Para hacerlo más simple, lo llamaremos router. Este router es el que asigna las direcciones de IP locales.

El router resuelve ciertos problemas de seguridad cuando trabaja con una WAN, permite expandir las direcciones de IP locales, y ayuda a organizar las conexiones WAN de la red local. Pero al mismo tiempo, deforma el sentido inicial de la WAN que implica la posibilidad de una conexión directa entre pares de cualquier par de ordenadores.

Este efecto se provoca por el hecho de que casi cualquier router realiza la llamada traducción de dirección de red (en inglés, network address translation (NAT)). La dirección de la red se representa por la tupla <protocolo, IP, puerto>. El router puede cambiar cualquier elemento de esta tupla, todo depende del modelo particular del router.

En este caso, el ordenador que accede a la WAN desde la LAN no tiene todos los beneficios que proporciona la WAN pura. La gran mayoría de los routers tienen una característica OUTBOUND que permite al router recordar la dirección del cliente LAN que dirige la red WAN global desde LAN con alguna petición.

Gracias a esta característica, el router puede enviar al cliente toda la información que ha recibido a través de otro router como respuesta a la petición del cliente. De este modo, el cliente LAN puede conectarse a los servidores WAN. Sin embargo, puede que esto no sea siempre cierto, ya que por cuestiones de seguridad y disciplina de trabajo, algunas redes pueden estar bloqueadas a hardwares.

Por lo tanto, para organizar un servidor en un ordenador LAN hay que configurar el llamado desvío de puerto. Como para el ejemplo de este artículo, en el caso más simple de un ordenador LAN, necesita desviar el puerto número 2 000. Puede hacerlo usted mismo, conectando el router en la mini site en el buscador, o puede acudir a un profesional. Lo más probable es que esta mini site está disponible en 192.168.1.1.

Todo esto debe considerarse si quiere tener la posibilidad de intercambiar información a través de una WAN.

En la siguiente versión del artículo, consideraremos el tipo de conexión entre pares (p2p).

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1361

Archivos adjuntos |
EXE.zip (21.35 KB)
FastStart.zip (28.26 KB)
NetServerClient.zip (56.32 KB)
Tres aspectos de la Automatización manual del trading. Primera parte: Trading Tres aspectos de la Automatización manual del trading. Primera parte: Trading
Este artículo es el primero de una serie de artículos sobre trading manual en la plataforma MetaTrader 4. Cada uno de los artículos se destinará a uno de los siguientes aspectos: automatización del trading manual, estado actual de la muestra de trade automatizado, y automatización de los informes de los resultados de trade. En este artículo, presentaré un método interesante para crear un AE controlado manualmente por un trader.
La sandbox aleatoria La sandbox aleatoria
El artículo incluye una "sandbox" interactiva como archivo Excel que simula datos de backtest de un Asesor Experto aleatorio. Los lectores pueden utilizar esto para ayudarse a explorar y comprender mejor el funcionamiento de los parámetros del AE por defecto con MetaTrader. El texto del artículo está diseñado para guiar al usuario a través de esta experiencia.
Sistema de trading mecánico "Triángulo de Chuvashov" Sistema de trading mecánico "Triángulo de Chuvashov"
Les voy a dar un resumen y el código de programa del sistema de trading mecánico basado en las ideas de Stanislav Chuvashov. La construcción del triángulo se basa en la intersección de dos líneas de tendencias construidas por los fractales más altos y los más bajos.
MetaTrader 4 en Linux MetaTrader 4 en Linux
En este artículo, explicaremos cómo instalar fácilmente MetaTrader 4 en las populares versiones de Linux Ubuntu y Debian. Estos sistemas se usan ampliamente no solo en el hardware de los servidores, sino también en los ordenadores habituales de los tráders.