記事"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">符号なしLONG。この型はWinDef.hで次のように宣言されている: typedef unsigned long ULONG;

となっていますが、よくわかりません。


というわけで:

もし私が正しければ、ここに無駄にulongを置くべきだった:

struct sockaddr_in
  {
   ushort            sin_family;
   ushort            sin_port;
   /*ulong*/uint     sin_addr; //構造体 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:port" フォーマットのアドレス
  TCP_Client(string server_address);
  ~TCP_Client();
  // サーバーへの接続がアクティブであれば真を返す。
  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:

どのようなタスクに使うのか、教えていただけますか?記事中にもリクエストがあります

私にとって便利な場所は思いつきません。

私はリナックスを使っているので、一般的にipcは非自明なタスクになります(wine下のターミナルと リナックスのexe間の 通信)。そしてネットワーク経由のipcは普遍的な方法だ。私はµlスクリプトを同じコンピュター上のループバック(127.0.0.1)経由でlinuxプログラムに接続している。基本的に、私はターミナル用のlinux apiを書きました(µlスクリプトはリクエストを処理し、価格データを送信したり、注文を出したりします)。

私の状況では、これが私が試した中で最良のIPC方法です。そして、私は自分の開発したものをµlに移したくありません - 原則的に特定の言語に縛られたくないのです。

 
pavlick_:

私はリナックスを使っているので、一般的にipcは自明なことではありません(ワイン下のターミナルとリナックスexe間の通信)。そしてネットワーク経由のipcは普遍的な方法だ。私はµlスクリプトを同じコンピュター上のループバック(127.0.0.1)経由でlinuxプログラムに接続している。基本的に、私はターミナル用のlinux apiを書きました(µlスクリプトはリクエストを処理し、価格データを送信したり、注文を出したりします)。

私の状況では、これが私が試した中で最良のIPC方法です。私は自分の開発をµlに移したくありません - 原則的に特定の言語に縛られたくないのです。

素晴らしい記事だ!どのプラットフォームでも、あなた自身のトレーディング・ユニバーサルAPIを手に入れることができる。そして、あるプラットフォームに対しては、そのプラットフォーム自体のAPIでレシーバー/トランスミッターを書くだけです。

そして、どんな言語でもTSを書くことができる。プログラマーとはそういうものだ!

見返りはレイテンシーだけだ。だから、非常に狭い種類のTCには使えない。

 
同じようにウェブ・ソケットを扱うクラスを書くことは可能ですか?
 
この記事はとても興味深く、参考になります。
実際に実装してみましたが、しばらくするとパケットが途切れ始めます。そして、ログから判断すると、最初はサーバー部分が「停止」し、クライアント部分は、この時点ではすべてが問題ないと思い続けている。
if(client==INVALID_SOCKET) StartClient(Host,Port);
をチェックするクライアント部分のコードが何も示さないからである。つまり、クライアントは、パケットを送信する前や送信している瞬間でさえ、サーバとの接続が切れていることを診断できないのです。

おそらく、サーバソケットの動作可能性を事前にチェックするために、"CheckSocket "のような関数を追加する必要があるのではないでしょうか?その場合、どのように実装すればよいのでしょうか?