Discussão do artigo "Trabalhando Com Soquetes em MQL, ou como se tornar um provedor de sinal" - 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;

mas no artigo.

#define  SOCKET           uint
// mas
#define  DWORD_PTR         ulong

Você precisa dos meus comentários aqui? Estou vinculando o código mql a um código externo e, paralelamente, analiso seus desenvolvimentos, encontro erros e não posso escrever aqui.

 

Tudo bem, os comentários são bem-vindos.

Estou enviando as edições de tipo para o artigo.

Usarei 64 bits nos exemplos

 
Não se esqueça de escrever explicitamente sobre bitness no artigo. Algo como: "código para x64" ou faça uma alteração nas macros para compilar para arquiteturas diferentes. A propósito, o que é sizeof(ULONG) no x64? Tenho alguns dados contraditórios. Por um lado, deve ser sempre 4, o modelo LLP64 no win sugere isso, e o msdn escreve:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx.
ULONG:<br/ translate="no">Um LONG sem sinal. O intervalo é de 0 a 4294967295 decimal. Esse tipo é declarado em WinDef.h da seguinte forma: typedef unsigned long ULONG;

mas não tenho certeza.


ENTÃO:

se eu estiver certo, você colocou ulong aqui 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...
 
Sim, e essa estrutura também não foi usada nos exemplos.
 

Eu tenho um 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:
  // Endereço no formato "IPv4:port
  TCP_Client(string server_address);
  ~TCP_Client();
  // Retorna true se a conexão com o servidor estiver ativa
  bool good()const;
  // Recebimento de um bloco de dados. No início de cada bloco, deve haver um bloco 4-x
  // Número inteiro de bytes cujo valor é igual ao tamanho do bloco. Retorna
  // o tamanho do bloco recebido ou 0;
  uint recv(char &buf[]);
  // Enviar bloco. 4 bytes de tamanho serão adicionados ao início do bloco.
  // Retorna o tamanho do bloco enviado ou 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("A conexão foi cortada.");
  else
    Alert("ok");
}

Não preciso de um servidor no µl, portanto, apenas um cliente. Testado superficialmente.

ZЫЫ: Obrigado pelo artigo.
 
pavlick_:

Tenho um cliente TCP síncrono desse tipo:

Você poderia compartilhar para quais tarefas vai usá-lo? Há até mesmo uma solicitação no artigo

Se você também tiver ideias de aplicativos, compartilhe-as nos comentários do artigo

Não consigo pensar em nenhum aplicativo em que isso seria conveniente para mim.

 
fxsaber:

Você poderia compartilhar para quais tarefas você vai usá-lo? Há até uma solicitação no artigo

Não consigo pensar em nenhum lugar onde isso seria conveniente para mim.

Estou no Linux, portanto, o ipc em geral se torna uma tarefa não trivial (comunicação entre o terminal no wine e o linuex exe). E o ipc em uma rede é uma forma universal. Conecto o script µl ao programa Linux via loopback (127.0.0.1) no mesmo computador. Basicamente, escrevi uma API do Linux para o terminal (o script µl lida com solicitações e envia dados de preço ou faz pedidos).

Em minha situação, essa é a melhor maneira de IPC que já experimentei. E não quero transferir meus desenvolvimentos para o µl - não quero ficar preso a uma linguagem específica, por uma questão de princípio.

 
pavlick_:

Estou no Linux e, portanto, o ipc em geral se torna uma tarefa não trivial (comunicação entre o terminal no wine e o linuex exe). E o ipc pela rede é uma forma universal. Conecto o script µl ao programa Linux via loopback (127.0.0.1) no mesmo computador. Basicamente, escrevi uma API do Linux para o terminal (o script µl lida com solicitações e envia dados de preço ou faz pedidos).

Em minha situação, essa é a melhor maneira de IPC do que eu tentei. Não quero transferir meus desenvolvimentos para o µl - não quero ficar vinculado a uma linguagem específica, por uma questão de princípio.

Seria um ótimo artigo! Você obtém sua própria API universal de negociação para qualquer plataforma. E para uma plataforma, você escreve apenas um receptor/transmissor na API da própria plataforma.

E você pode escrever TS em qualquer idioma. Os programadores são assim!

O retorno é apenas em latência. É por isso que ele não funcionará para um tipo muito restrito de TC - e não há problema nisso.

 
É possível escrever uma classe para trabalhar com soquetes da Web da mesma maneira?
 
O artigo é muito interessante e informativo. Pretendo usar a tecnologia de soquete para transferir do servidor VPS com terminais MT-5 para o servidor com informações do banco de dados MS-SQL sobre o status financeiro das contas no final do dia/semana/mês.
Implementado na prática, mas a prática mostra que depois de algum tempo os pacotes começam a ser perdidos. E, a julgar pelos logs, a princípio a parte do servidor "para", e as partes do cliente nesse momento continuam a pensar que está tudo bem, porque o código da parte do cliente da verificação do tipo
if(client==INVALID_SOCKET) StartClient(Host,Port);
não fornece nada. Ou seja, os clientes não conseguem diagnosticar a perda de conexão com o servidor antes de enviar e mesmo no momento do envio dos pacotes.

Talvez seja necessário adicionar alguma função como "CheckSocket" para a verificação preliminar da operacionalidade do soquete do servidor? Como implementá-la então?