Discusión sobre el artículo "Trabajando con sockets en MQL, o Cómo convertirse en proveedor de señales" - página 3

 
// basetsd.h поставляемого с wine'ом
#if defined(__midl) || defined(__WIDL__)
  typedef unsigned __int3264 UINT_PTR, *PUINT_PTR;
  typedef unsigned __int3264 ULONG_PTR, *PULONG_PTR;
  typedef ULONG_PTR                   DWORD_PTR, *PDWORD_PTR;
 #elif defined(_WIN64)
  typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
#else
  typedef unsigned long UINT_PTR, *PUINT_PTR;
#endif

typedef UINT_PTR SOCKET;

sino en el artículo.

#define  SOCKET           uint
// pero
#define  DWORD_PTR         ulong

¿Necesitas mis comentarios aquí? Estoy enlazando código mql con código externo, paralelamente miro tus desarrollos, encuentro errores, puede que no escriba aquí.

 

está bien, los comentarios son bienvenidos.

Estoy enviando las ediciones de tipo al artículo.

Usaré 64 bits en los ejemplos

 
No olvides escribir explícitamente sobre bitness en el artículo. Algo como: "código para x64" o hacer un interruptor en las macros para compilar para diferentes arquitecturas. Por cierto, ¿qué es sizeof(ULONG) en x64? Tengo datos contradictorios. Por un lado debería ser 4 siempre, el modelo LLP64 en win lo insinúa, y msdn escribe:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx.
ULONG:<br/ translate="no">Un LONG sin signo. El rango es de 0 a 4294967295 decimal Este tipo se declara en WinDef.h como sigue: typedef unsigned long ULONG;

pero no estoy seguro.


ENTONCES

si estoy en lo cierto, has metido ulong aquí para nada:

struct sockaddr_in
  {
   ushort            sin_family;
   ushort            sin_port;
   /*ulong*/uint     sin_addr; //struct in_addr == 4 bytes
   char              sin_zero[8];
  };
/*ulong*/ uint inet_addr(char& cp[]);
Windows Data Types (Windows)
  • msdn.microsoft.com
The data types supported by Windows are used to define function return values, function and message parameters, and structure members. They define the size and meaning of these elements. For more information about the underlying C/C++ data types, see Data Type Ranges. The following table contains the following types: character, integer...
 
Sí, y esta estructura tampoco se utilizó en los ejemplos.
 

Tengo un cliente TCP síncrono:

// tcp_client.mqh

//#define X64
#define MAKEWORD(low, high) ((ushort) ((low & 0xff) | ((ushort)high << 8)))
#ifdef X64
  #define SOCKET          ulong
#else
  #define SOCKET          uint
#endif
#define INVALID_SOCKET    (SOCKET)(~0)
#define WSA_DATA_SZ       420

struct sockaddr_in
{
  short sin_family;
  ushort sin_port;
  uint sin_addr;
  char sin_zero[8];
};

#import "ws2_32.dll"
  int WSAStartup(ushort wVersionRequested, uchar &lpWSAData[]);
  int WSACleanup(void);
  SOCKET socket(int af, int type, int protocol);
  uint inet_addr(char &cp[]);
  ushort htons(ushort hostshort);
  int bind(SOCKET s, sockaddr_in &name, int namelen);
  int connect(SOCKET s, sockaddr_in &name, int namelen);
  int closesocket(SOCKET s);
  int recv(SOCKET s, char &buf[], int len, int flags);
  int send(SOCKET s, char &buf[], int len, int flags);
#import

class TCP_Client
{
  SOCKET socket;
  uchar state;
  TCP_Client(const TCP_Client&);
  TCP_Client operator=(TCP_Client &);
public:
  // Dirección en formato "IPv4:puerto
  TCP_Client(string server_address);
  ~TCP_Client();
  // Devuelve true si la conexión con el servidor está activa
  bool good()const;
  // Recepción de un bloque de datos. Al principio de cada bloque debe haber un 4-x
  // entero de bytes cuyo valor es igual al tamaño del bloque. Devuelve
  // el tamaño del bloque recibido o 0;
  uint recv(char &buf[]);
  // Enviar bloque. Se añadirán 4 bytes de tamaño al principio del bloque.
  // Devuelve el tamaño del bloque enviado o 0;
  uint send(char &buf[], uint len);
};

TCP_Client::TCP_Client(string server_address): socket(INVALID_SOCKET), state(0)
{
  uchar wsa_buf[WSA_DATA_SZ];
  if( WSAStartup(MAKEWORD(2,2), wsa_buf) )
    return;
  this.state |= B'1';
  
  if( (this.socket = socket(2, 1, 0)) == INVALID_SOCKET)
    return;
  this.state |= B'10';
  
  if(true)
  { 
    string server_address_ar[];
    if(StringSplit(server_address, ':', server_address_ar) != 2)
      return;
    char ch_addr[];
    StringToCharArray(server_address_ar[0], ch_addr);
    sockaddr_in addr = {0};
    addr.sin_family = 2;
    addr.sin_addr = inet_addr(ch_addr);
    addr.sin_port = htons( (ushort)StringToInteger(server_address_ar[1]) );
    if( connect(this.socket, addr, sizeof(addr)) )
      return;
    this.state |= B'100';
  }
}

TCP_Client::~TCP_Client()
{
  if( bool(this.state & B'10') )
    closesocket(this.socket);
  if( bool(this.state & B'1') )
    WSACleanup();
}

bool TCP_Client::good()const  {return this.state == B'111';}

uint TCP_Client::recv(char &buf[])
{
  struct Data_sz_int    {uint sz;} sz_int = {};
  if(true)
  {
    struct Data_sz_char   {char sz[4];} sz_char;
    int read = recv(this.socket, sz_char.sz, sizeof(sz_char), 8);
    if(read != sizeof(sz_char))
    {
      this.state &= B'11';
      return 0;
    }
    sz_int = (Data_sz_int)sz_char;
  }
  
  if( (uint)ArraySize(buf) < sz_int.sz )
    if(ArrayResize(buf, sz_int.sz) != sz_int.sz)
      return 0;
  int read = recv(this.socket, buf, sz_int.sz, 8);
  if(read != sz_int.sz)
  {
    this.state &= B'11';
    return 0;
  }
  return read;
}

uint TCP_Client::send(char &buf[], uint len)
{
  if(true)
  {
    struct Data_sz_int    {uint sz;} sz_int;
    sz_int.sz = len;
    struct Data_sz_char   {char sz[4];} sz_char;
    sz_char = (Data_sz_char)sz_int;
    int sent = send(this.socket, sz_char.sz, sizeof(Data_sz_char), 0);
    if( sent != sizeof(Data_sz_char) )
    {
      this.state &= B'11';
      return 0;
    }
  }
  
  int sent = send(this.socket, buf, len, 0);
  if( sent != len )
  {
    this.state &= B'11';
    return 0;
  }
  return sent;
}

//------------------------------------------------------------
// main.mq4

#property strict
#include "tcp_client.mqh"

void OnStart()
{
  TCP_Client s("127.0.0.1:10500");
  if( ! s.good() )
    return;
    
  char buf[];
  StringToCharArray("Hello world", buf);
  // Enviar 4 bytes + ArraySize(buf)
  if( s.send(buf, ArraySize(buf)) != ArraySize(buf) )
    Alert("La conexión se ha cortado".);
  else
    Alert("ok");
}

No necesito un servidor en µl, así que sólo un cliente. Probado superficialmente.

ZЫЫ: Gracias por el artículo.
 
pavlick_:

Tengo un cliente TCP síncrono de este tipo:

¿Podrías compartir para qué tareas lo vas a utilizar? Incluso hay una solicitud en el artículo

Si usted también tiene ideas de aplicación - compartirlas en los comentarios al artículo

No puedo pensar en ninguna aplicación en la que sería conveniente para mí.

 
fxsaber:

¿Podrías compartir para qué tareas lo vas a utilizar? Incluso hay una petición en el artículo

No se me ocurre ningún sitio donde me convenga.

Estoy en linux, de ahí que ipc en general se convierta en una tarea no trivial (comunicación entre terminal bajo wine y linuex exe). E ipc sobre una red es una forma universal. Conecto el script µl al programa linux a través de loopback (127.0.0.1) en el mismo ordenador. Básicamente, escribí una api de linux para el terminal (el script µl gestiona las peticiones y envía los datos de precios o coloca las órdenes).

En mi situación esta es la mejor manera de IPC de lo que he probado. Y no quiero transferir mis desarrollos a µl: no quiero estar atado a un lenguaje concreto, por una cuestión de principios.

 
pavlick_:

Estoy en linux, por lo tanto ipc en general se convierte en una tarea no trivial (comunicación entre terminal bajo wine y linuex exe). E ipc sobre la red es una forma universal. Conecto el script µl al programa linux a través de loopback (127.0.0.1) en el mismo ordenador. Básicamente, escribí una api de linux para el terminal (el script µl gestiona las peticiones y envía los datos de precios o coloca las órdenes).

En mi situación, ésta es la mejor forma de IPC que he probado. No quiero transferir mis desarrollos a µl, no quiero estar atado a un lenguaje concreto, por una cuestión de principios.

Sería un gran artículo. Tienes tu propia API universal de comercio para cualquier plataforma. Y para una plataforma escribes sólo un receptor/transmisor en la API de la propia plataforma.

Y puedes escribir TS en cualquier lenguaje. ¡Los programadores son así!

La contrapartida está sólo en la latencia. Por eso no funcionará para un tipo muy estrecho de TC - y eso está bien.

 
¿Es posible escribir una clase para trabajar con web sockets de la misma manera?
 
El artículo es muy interesante e informativo. Tengo la intención de utilizar la tecnología de socket para transferir desde el servidor VPS con terminales MT-5 al servidor con base de datos MS-SQL información sobre el estado financiero de las cuentas al final del día / semana / mes.
Implementado en la práctica, pero la práctica muestra que después de algún tiempo los paquetes comienzan a perderse. Y a juzgar por los registros en un primer momento la parte del servidor "se detiene", y las partes cliente en este momento siguen pensando que todo está bien, porque el código de la parte cliente de la comprobación de tipo
if(client==INVALID_SOCKET) StartClient(Host,Port);
no da nada. Es decir, los clientes no pueden diagnosticar la pérdida de conexión con el servidor antes de enviar e incluso en el momento de enviar paquetes.

¿Tal vez sea necesario añadir alguna función como "CheckSocket" para la comprobación preliminar de la operatividad del socket del servidor? ¿Cómo implementarlo entonces?