Diskussion zum Artikel "Arbeiten mit Sockets in MQL, oder Wie man ein Signalprovider wird" - Seite 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;

sondern in dem Artikel.

#define  SOCKET           uint
// aber
#define  DWORD_PTR         ulong

Brauchen Sie meine Kommentare hier überhaupt? Ich verbinde mql-Code mit externem Code, parallel schaue ich mir Ihre Entwicklungen an, finde ich Fehler, darf ich hier nicht schreiben.

 

Es ist okay, Kommentare sind willkommen.

Ich sende die Änderungen an den Artikel.

Ich werde 64 Bit in den Beispielen verwenden

 
Vergessen Sie nicht, in Ihrem Artikel explizit auf die Bittauglichkeit hinzuweisen. Etwas wie: "Code für x64" oder einen Schalter auf Makros, um für verschiedene Architekturen zu kompilieren. Übrigens, was ist sizeof(ULONG) auf x64? Ich habe einige widersprüchliche Daten. Einerseits sollte es immer 4 sein, das LLP64-Modell in win deutet darauf hin, und msdn schreibt:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx.
ULONG:<br/ translate="no">Ein LONG ohne Vorzeichen. Der Bereich ist 0 bis 4294967295 dezimal Dieser Typ ist in WinDef.h wie folgt deklariert: typedef unsigned long ULONG;

aber ich bin mir nicht sicher.


SO:

Wenn ich richtig liege, haben Sie ulong hier umsonst reingepackt:

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...
 
Ja, und diese Struktur wurde auch in den Beispielen nicht verwendet.
 

Ich habe einen solchen synchronen TCP-Client:

// 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:
  // Adresse im Format "IPv4:port"
  TCP_Client(string server_address);
  ~TCP_Client();
  // Gibt true zurück, wenn die Verbindung zum Server aktiv ist
  bool good()const;
  // Empfangen eines Datenblocks. Am Anfang eines jeden Blocks muss ein 4-x
  // Byte-Ganzzahl, deren Wert gleich der Blockgröße ist. Rückgabe
  // die Größe des empfangenen Blocks oder 0;
  uint recv(char &buf[]);
  // Block senden. Am Anfang des Blocks werden 4 Bytes der Größe hinzugefügt.
  // Gibt die Größe des gesendeten Blocks oder 0 zurück;
  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);
  // 4 Bytes senden + ArraySize(buf)
  if( s.send(buf, ArraySize(buf)) != ArraySize(buf) )
    Alert("Die Verbindung wurde unterbrochen.");
  else
    Alert("ok");
}

Ich brauche keinen Server auf µl, also nur einen Client. Oberflächlich getestet.

ZЫЫ: Danke für den Artikel.
 
pavlick_:

Ich habe einen solchen synchronen TCP-Client:

Könnten Sie uns mitteilen, für welche Aufgaben Sie ihn verwenden werden? Es gibt sogar eine Anfrage in dem Artikel

Wenn Sie auch Ideen für Anwendungen haben - teilen Sie sie in den Kommentaren zum Artikel mit

Mir fällt keine Anwendung ein, bei der es für mich sinnvoll wäre.

 
fxsaber:

Können Sie uns mitteilen, für welche Aufgaben Sie es verwenden werden? Es gibt sogar eine Anfrage in dem Artikel

Ich kann mir nicht vorstellen, wo es für mich praktisch wäre.

Ich bin in linux, daher ipc im Allgemeinen wird eine nicht-triviale Aufgabe (Kommunikation zwischen Terminal unter Wein und linuex exe). Und ipc über ein Netzwerk ist ein universeller Weg. Ich verbinde das µl-Skript mit dem Linux-Programm über Loopback (127.0.0.1) auf demselben Computer. Im Grunde habe ich eine Linux-API für das Terminal geschrieben (das µl-Skript bearbeitet Anfragen und sendet Kursdaten oder erteilt Aufträge).

Nach allem, was ich bisher ausprobiert habe, ist dies in meiner Situation die beste Art der IPC. Und ich möchte meine Entwicklungen nicht auf µl übertragen - ich möchte prinzipiell nicht an eine bestimmte Sprache gebunden sein.

 
pavlick_:

Ich arbeite unter Linux, daher wird ipc im Allgemeinen zu einer nicht-trivialen Aufgabe (Kommunikation zwischen Terminal unter Wine und linuex exe). Und ipc über das Netzwerk ist ein universeller Weg. Ich verbinde das µl-Skript mit dem Linux-Programm über Loopback (127.0.0.1) auf demselben Computer. Im Grunde habe ich eine Linux-API für das Terminal geschrieben (das µl-Skript bearbeitet Anfragen und sendet Kursdaten oder erteilt Aufträge).

Nach allem, was ich bisher ausprobiert habe, ist dies in meiner Situation die beste Art der IPC. Ich möchte meine Entwicklungen nicht auf µl übertragen - ich möchte prinzipiell nicht an eine bestimmte Sprache gebunden sein.

Das wäre ein toller Artikel! Sie erhalten Ihre eigene universelle Handels-API für jede Plattform. Und für eine Plattform schreiben Sie nur einen Receiver/Transmitter auf der API der Plattform selbst.

Und Sie können TS in jeder Sprache schreiben. Programmierer sind eben so!

Payback ist nur in der Latenzzeit. Deshalb wird es für eine sehr enge Art von TC nicht funktionieren - und das ist in Ordnung.

 
Ist es möglich, eine Klasse zu schreiben, die auf die gleiche Art und Weise mit Web-Sockets arbeitet?
 
Der Artikel ist sehr interessant und informativ. Ich habe vor, die Socket-Technologie zu verwenden, um vom VPS-Server mit MT-5-Terminals auf den Server mit MS-SQL-Datenbank Informationen über den Finanzstatus der Konten am Ende des Tages/Woche/Monats zu übertragen.
In der Praxis umgesetzt, aber die Praxis zeigt, dass nach einiger Zeit Pakete zu verlieren beginnen. Und nach den Protokollen zu urteilen, bleibt der Serverteil zunächst "stehen", und die Clientteile denken zu diesem Zeitpunkt weiterhin, dass alles in Ordnung ist, weil der Code des Clientteils der Prüfung vom Typ
if(client==INVALID_SOCKET) StartClient(Host,Port);
nichts hergibt. D.h. die Clients können den Verlust der Verbindung mit dem Server vor dem Senden und sogar im Moment des Sendens von Paketen nicht feststellen.

Vielleicht ist es notwendig, eine Funktion wie "CheckSocket" für die vorläufige Prüfung der Funktionsfähigkeit des Serversockets hinzuzufügen? Wie kann man sie dann implementieren?