文章 "在MQL中操作套接字,或者如何成为信号提供者" - 页 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;

但在文章中。

#define  SOCKET           uint
// 但
#define  DWORD_PTR         ulong

您需要我在这里发表评论吗?我正在将 mql 代码与外部代码连接起来,同时我也在查看您的开发成果,如果发现错误,我可能不会在这里写。

 

没关系,欢迎发表评论。

我正在发送文章的类型编辑。

我将在示例中使用 64 位

 
别忘了在文章中明确写出比特率。比如:"为 x64 编写代码",或者在宏上做一个开关,以便为不同的体系结构编译。顺便问一下,x64 上的 sizeof(ULONG) 是多少?我有一些相互矛盾的数据。一方面,它始终应该是 4,win 中的 LLP64 模型暗示了这一点,而 msdn 写道:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx。
ULONG:<br/translate="no">无符号长。该类型在 WinDef.h 中声明如下:typedef unsigned long ULONG;

但我不确定。


那么

如果我是对的,你在这里白白塞进了 ulong:

struct sockaddr_in
  {
   ushort            sin_family;
   ushort            sin_port;
   /*ulong*/uint     sin_addr; //struct in_addr == 4 字节
   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...
 
是的,例子中也没有使用这种结构。
 

我有这样一个同步 TCP 客户端:

// 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:
  // 采用 "IPv4:端口 "格式的地址
  TCP_Client(string server_address);
  ~TCP_Client();
  // 如果与服务器的连接处于活动状态,则返回 true
  bool good()const;
  // 接收数据块。每个数据块的开头必须有一个 4-x
  // 值等于块大小的字节整数。返回值
  // 接收数据块的大小或 0;
  uint recv(char &buf[]);
  // 发送数据块。数据块的开头将增加 4 个字节的大小。
  // 返回发送区块的大小或 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);
  // 发送 4 个字节 + ArraySize(buf)
  if( s.send(buf, ArraySize(buf)) != ArraySize(buf) )
    Alert("连接已被切断");
  else
    Alert("ok");
}

我不需要 µl 上的服务器,所以只需要一个客户端。我只是做了表面测试。

ZЫЫ: 感谢您的文章。
 
pavlick_:

我有这样一个同步 TCP 客户端:

您能分享一下您打算将它用于哪些任务吗?文章中甚至有一个请求

如果您也有应用方面的想法,请在文章评论中与我们分享。

我想不出有什么应用对我来说是方便的。

 
fxsaber:

您能分享一下您打算将它用于哪些任务吗?文章中甚至有这样的要求

我想不出它在哪里会给我带来方便。

我使用的是 linux 系统,因此在一般情况下,ipc 成为了一项非同小可的任务( wine 下的终端 和 linuex exe之间进行 通信)。而通过网络进行 IPC 是一种通用方式。我通过同一台计算机上的环回(127.0.0.1)将 µl 脚本连接到 linux 程序。基本上,我为终端编写了一个 linux api(µl 脚本处理请求并发送价格数据或下单)。

在我的情况下,这是我尝试过的最好的 IPC 方式。而且我不想将我的开发成果转移到 µl 上,因为原则上我不想被某种特定的语言所束缚。

 
pavlick_:

我使用的是 linux 系统,因此在一般情况下,ipc 成为一项非同小可的任务(在 wine 下的终端和 linuex exe 之间进行通信)。而通过网络进行 IPC 是一种通用方法。我通过同一台计算机上的环回(127.0.0.1)将 µl 脚本连接到 linux 程序。基本上,我为终端编写了一个 linux api(µl 脚本处理请求并发送价格数据或下单)。

在我的情况下,这是我尝试过的最好的 IPC 方式。我不想把我的开发成果转移到 µl 上 - 原则上,我不想被某种特定的语言所束缚。

这将是一篇很好的文章!您可以在任何平台上获得自己的交易通用 API。对于一个平台,您只需在平台本身的 API 上编写接收器/发送器。

您可以用任何语言编写 TS。程序员就是这样!

回报只体现在延迟上。这就是为什么它不适用于非常狭窄的 TC 类型--这也没关系。

 
是否有可能编写一个类,以同样的方式使用网络套接字?
 
这篇文章非常有趣,信息量很大。我计划使用套接字技术从装有 MT-5 终端的VPS 服务器 向装有 MS-SQL 数据库的服务器传输有关日/周/月末账户财务状况的信息。
已在实践中实施,但实践表明,一段时间后数据包开始丢失。根据日志判断,一开始服务器部分会 "停止",而客户部分此时仍认为一切正常,因为客户部分的检查类型代码
if(client==INVALID_SOCKET) StartClient(Host,Port);
的客户端部分代码没有给出任何结果。也就是说,客户端在发送数据包之前,甚至在发送数据包的过程中,都无法判断是否与服务器失去了连接。

也许有必要添加一些类似于 "CheckSocket "的函数来初步检查服务器套接字的可操作性?如何实现?