2016-05-21 8 views
1

私は10年ほど前にASIOを使っていましたが、私は以前ブースト・ネットローク・ライブラリがありました。 (例えば、ACE、nodejsなど)を使用することができます。今ではASIOを使って簡単なコードを書いてみたいと思います。シンプルなネットワーキングtcpとBoost.ASIOを使ったサーバとの通信

まずはシンプルな同期コードですが、これはBSD/winsockコードのほんの数行に過ぎず、asioを使った完全な混乱です。すべてのコードだけでなく、実際のロジックを隠す乱雑なものの一口のように見えるだけでなく、私は実際にペストのように避けたいいくつかのものを使用するように強制します。

だから、最初は、私が何をする必要があるかについて説明します。名前空間の話の一口のように見えますが、多かれ少なかれOKであっても、この部分ASIOでは1234::

1)mymagichost.comでサーバーに接続
#include <boost/asio.hpp> 
// I'm scared what the code would look like without this one. 
using boost::asio::ip::tcp; 
int main() 
{ 
    boost::asio::io_service io_service; 
    tcp::socket sock(io_service); 
    tcp::resolver resolver(io_service); 
    boost::asio::connect(sock, resolver.resolve(
     tcp::resolver::query(tcp::v4(), "mymagichost.com", "1234"))); 
} 

私は単純に、私がintとして1234を渡すことができない可能性があります。つまり、ここで文字列を渡すと、サービス名の巨大なリストが私のバイナリに取り込まれます私はポート1234が必要ですか? WTF?

接続したとき、私は、サーバーとのこの単純な話を実行する必要があります。

// when I start talking I say PING\n to the server 
"PING\n" 

// it replies back with 64-bit unsigned int id 
"PONG <connection id>\n" 

// I ask server to execute command, where <cmd id> 
// is an int and connection id is that number that 
// server sent to me in PONG. 
"COMMAND <cmd id>:<connection id>\n" 

// server executes my command 
"OK <message id>\n<binary data until remote closes socket>" 

ブロックBSDの靴下では、コードの10〜20行のようなものです:どのようにこれができるので

void talk(int sock) // consider it pseudo-code 
{ 
    char buf[1024]; 
    int cmd_id = 1234; 
    send(sock, "PING\n", 5, 0); 
    unsigned long long connection_id, msg_id; 
    recv(sock, buf, sizeof(buffer), 0); 
    sscanf(buf, "PONG %llu\n", &connection_id); 
    int n = sprintf(buf, "COMMAND %u:llu\n", cmd_id, connection_id); 
    send(sock, buf, n, 0); 
    vector<char> data; 
    for (; (n = recv(sock, buf, sizeof(buf), 0)) > 0;) 
     data.insert(data.end(), buf, buf+n); 
    sscanf(buf, "OK %llu\n%n", &msg_id, &n); 
    char *binary_data = buf.data()+n; 
    int binary_data_size = data.size()-n; 
} 

同期asioで行われますか? 私のBSDコードには、多くの欠点があります。後続の '\ n'が受信されるまで受信時にループする必要があります(おそらくこれは単純な例です)。データを受信するための多くの機能の中で まさにそのものがある:

boost::asio::read_until(sock, buf, '\n'); 

しかし、ブースト:: ASIO ::読みとは異なり、read_untilは(私は実際に疫病のように避けたいもの)のみストリームバッファ受け付けます。私はちょうど私が自分自身の固定バッファを使用することを許可しない理由はない、それはasio devは私の足で撮影から私を防ぐことを決めたのでですか?私はまだヌルポインタを尊重することができますしたいです。とにかく、大したことではなく、私はstreambufを使うことができますが、ここでは本当に醜いものになります。 ドキュメントによると、サーバーで最後に '\ n'が返された後、OK応答バッファに実際にはさらに多くのデータが含まれている可能性があります。here's what the docs say: "read_until操作が成功した場合、streambufには区切り文字を超えた追加データが含まれます。ストリームbufの中のデータを調べて次のread_untilオペレーションを調べます。 " サーバーからの最後のOK応答を処理した後、私は本当に選択肢がありませんが、残りのすべてのデータ(メグ)を読み込むために恐ろしいstreambufを使用し続けます。バッファ(文字列またはベクトル)。私がデータを読み終えたら、すべてのメソッドをストリームbufから取得するのが大変です。データを複数回コピーするか、istream_iterator/istreambuf_iteratorを使用してコンテナに追加してください。両方とも私の意見では非常に遅いです、私のビジュアルスタジオは文字通り数秒間ハングします(私は途中でデータのギグを受け取っていません)。

だから、asioでそれを処理する適切な方法は何ですか?

+1

ご質問ください。ラントはちょっと気にせず、説明するのに気をつけることもありません。 "other" libはおそらく 'cppnetlib'であり、依然として存在します。最近は他にもたくさん存在しています。 – sehe

+0

@sehe私はそれらが存在することを知っていますが、私はブーストを使用して完全にいくつかのテストプロジェクトを書こうと思っていました、それがポイントです。さもなければ私はasioに触れることはありません。 – Pavel

答えて

1

第1に、あなたが解決を求めているので、アドレスは数値であると仮定することはできません。リゾルバが、ポートが数字AFAICTであると見なせば、サービス定義のロードを避けることはできないということは何もありません。

第2に、ASIOにはいくつかのハイレベルプリミティブがあります。あなたはそれを使用することができます:

void talk(std::iostream& sock) // consider it pseudo-code 
{ 
    int cmd_id = 1234; 
    sock << "PING" << std::endl; 

    uint64_t connection_id; 

    if (sock >> connection_id) { 
     sock << "COMMAND " << cmd_id << ":" << connection_id << std::endl; 

     char buf[1024]; 
     std::vector<char> data; 
     // read till eof 
     while (sock.read(buf, sizeof(buf)) 
      data.insert(data.end(), buf, buf+sizeof(buf)); 
     data.insert(data.end(), buf, buf+sock.gcount()); 
    } 

    uint64_t msg_id; 
    int n; 
    if (sock >> qi::phrase_match("OK" >> qi::auto_ >> '\n' >> qi::auto_, qi::blank, msg_id, n)) { 
     // do something with n and msg_id 
    } 
} 

int main() { 
    boost::asio::ip::tcp::iostream s { "127.0.0.1", "1234" }; 
    talk(s); 
} 

は、あなたが精神なしでやってみたかった場合、あなたはおそらくgetlineと物事と同様のsscanf関数の仕掛けの周りハックうLive On Coliru

それを参照してください。

+0

ポートは文字列として渡されます。これは、すべてのサービス文字列がコンパイルされることを意味します(asioがOSを使用してサービス名を解決する場合を除き、IMOはそうではありません)。私はまた、ホスト名を解決することを求めています。これは、ポートを解決することとはまったく異なります。 – Pavel

+1

Asioがサービス名を解決するためにOSを使用しないことは、ポータブルTCPスタックがどのように動作するかというよりはむしろそうであろう。 – sehe

+0

このiostreamインターフェイスを使用すると、読み込みがスペースで区切られた大きなコマンドであることを除いて、簡単に動作させることができます。 – Pavel

関連する問題