locked
recv()関数で受信メッセージをすべて取得できません。 RRS feed

  • 質問

  • リモートサーバ(Windows)に接続して、send()関数で「dir」コマンドを送信した後で、recv(socket, (char*)message, 65536, 0)関数でコマンドdirの標準出力を取得したいです。しかし、もしdirの標準出力が多すぎる場合、部分内容しか取得できません。コマンドの標準出力をすべて取得する方法がありますか?

    例えば:

    ■ソースコード

    Socket socket = (int)socket(AF_INET, SOCK_STREAM, 0);
    略。。。
    addrSrv.sin_addr.S_un.S_addr = inet_addr(server);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(23);   =====>Windows自身のtelnet port
    略。。。
    connect(socket, (SOCKADDR)&addrSrv, sizeof(SOCKADDR));
    略。。。
    send(socket, (char )"dir\r\n", , 0);

    while (1) {

    recv(socket, (char)message, 65535, 0);

    //受信メッセージの長さが0の場合、無限ループを飛び出す。

    }

    ■コマンドdirの正常の戻り値は以下のように示す。(以下のdirの標準出力は例です。本当の内容は多いです。)

    =========================

     驱动器 C 中的卷没有标签。
     卷的序列号是 84EC-D9AB

     C:\Documents and Settings\linkage 的目录

    2009-11-13  10:20    <DIR>          .
    2009-11-13  10:20    <DIR>          ..
    2010-07-15  11:17    <DIR>          Favorites
    2009-11-09  14:05    <DIR>          funshion
    2009-08-12  10:03                12 intlname.ols
    2009-12-04  13:48    <DIR>          My Documents
    2009-07-24  15:30    <DIR>          「开始」菜单
    2009-12-04  13:56    <DIR>          桌面
                   1 个文件             12 字节
                   7 个目录 15,214,485,504 可用字节

    =========================

    ■しかし、recv()関数で取得の内容は以下のように示す。最後の部分標準出力しか取得できません。

    =========================

    2009-12-04  13:48    <DIR>          My Documents
    2009-07-24  15:30    <DIR>          「开始」菜单
    2009-12-04  13:56    <DIR>          桌面
                   1 个文件             12 字节
                   7 个目录 15,214,485,504 可用字节

     =========================

     

    • 編集済み 寒い夏 2010年7月16日 2:45
    2010年7月15日 5:03

回答

  • TCPなら、recvは何回も呼ぶ必要があります。
    厳密に何回必要かは、TCPでは規定されていないので、わからないのです。
    先頭に「長さ」を前置しておくとか、0x1Aが毎回最後を示すマーカーとして付与するとか、アプリケーションレベルのプロトコル決定が必要でしょう。


    jzkey
    • 回答の候補に設定 山本春海 2010年7月22日 6:15
    • 回答としてマーク 山本春海 2010年8月2日 7:38
    2010年7月15日 12:50
  • しかし、解決方法はまだわかりません。

    弱りましたね(vv;)。以下の部分でrecv()の戻り値 n には「受信したByte数」が
    戻ります。つまりmessageの先頭から n Byteまでが受信できたByte数です。
    出力する部分のコードが提示されていないので詳しくは言えませんが、
    こんな感じでやります。
    int n;
    while(1){
      n = recv(socket, (char)message, 65535, 0);
      //受信完了判定と脱出
      ・・・
        //以下で出力する
       Some_OutPut_Function( message, n); // 作ってね
    }
    ブロックモードとノンブロックモードでは動作が全く異なるので調べてみてください。
    尚、VS2008ならば、付属のドキュメントの「recv」の項目に、
    サンプルがあります。
    • 回答としてマーク 山本春海 2010年8月2日 7:38
    2010年7月26日 10:03

すべての返信

  • TCPなら、recvは何回も呼ぶ必要があります。
    厳密に何回必要かは、TCPでは規定されていないので、わからないのです。
    先頭に「長さ」を前置しておくとか、0x1Aが毎回最後を示すマーカーとして付与するとか、アプリケーションレベルのプロトコル決定が必要でしょう。


    jzkey
    • 回答の候補に設定 山本春海 2010年7月22日 6:15
    • 回答としてマーク 山本春海 2010年8月2日 7:38
    2010年7月15日 12:50
  • よく見ると、送信されたデータの後半部分だけが受信されています。

    TCPの場合、データの順番が制御されていて追い越しなどは発生しません。
    つまりこのような現象が観測できるということは、送信側が先頭部分を送信し忘れている(そもそも送信していない)か、もしくは受信側がデータを読み捨てているかのどちらかです。

    2010年7月22日 6:28
  • ああ…つまり recv の バッファ(message)をそのまま使っているという…

     

    それにしても、他のスレッドといい、レスしてくれない質問者さんですね。。

    • 編集済み anningo 2010年7月26日 9:38 フォントが意図しない大きさになっていたので修正
    2010年7月22日 7:05
  • 皆様、お疲れ様です

    ご回答、本当にありがとうございました。

    問題の発生原因を確認しましたが、解決方法はまだわかりません。

    原因:リモートサーバに接続して、コマンドを実行した後で、リモートサーバのコンソールウィンドウのデフォルトの「画面バッファサイズ」が小さすぎるので、コマンドの標準出力が多すぎる場合、コンソールウィンドウの内容を自動的に切り替えられました。最後部分の内容しか表示できません。受信側へ送信するとき、画面上の内容しか送信しない。それで、受信側は部分標準出力しか受信できません。

    しかし、解決方法はまだわかりません。

    2010年7月26日 9:11
  • しかし、解決方法はまだわかりません。

    弱りましたね(vv;)。以下の部分でrecv()の戻り値 n には「受信したByte数」が
    戻ります。つまりmessageの先頭から n Byteまでが受信できたByte数です。
    出力する部分のコードが提示されていないので詳しくは言えませんが、
    こんな感じでやります。
    int n;
    while(1){
      n = recv(socket, (char)message, 65535, 0);
      //受信完了判定と脱出
      ・・・
        //以下で出力する
       Some_OutPut_Function( message, n); // 作ってね
    }
    ブロックモードとノンブロックモードでは動作が全く異なるので調べてみてください。
    尚、VS2008ならば、付属のドキュメントの「recv」の項目に、
    サンプルがあります。
    • 回答としてマーク 山本春海 2010年8月2日 7:38
    2010年7月26日 10:03
  • ご返信、有難うございました。

    受信側のソースコードの問題ではない、送信側の問題です。リモートサーバでコマンドを実行すれば、Windows自身のコンソールウィンドウを利用する必要があります。コマンドの標準出力を全部取得したい場合、コンソールウィンドウの「画面バッファサイズ」を変更するなければなりません。でも、これは一番いい方法ではないと思います。そのほか方法でコマンドラインが実行できれば、一番いいと思います。

    2010年7月26日 15:19
  • こんにちは、寒い夏 さん。

    勝手ながら私のほうで、有効な情報と思われる投稿に回答としてマークさせていただきましたが、まだご不明点等あるかと思いますので、すでに投稿されている下記スレッドのほうで、続きをお願いいたします。
    恐れ入りますが、こちらのスレッドはロックさせていただきます。

     C/C++言語でWindowsのコンソールウィンドウの「画面バッファのサイズ」の修正方法について
     http://social.msdn.microsoft.com/Forums/ja-JP/vcgeneralja/thread/2efc59c5-4193-4fcb-a95c-b078add68785

    こちらのスレッドを参照されている方、投稿いただける方は、上記スレッドのほうにお願いいたします。
                                                         
    マイクロソフト株式会社 MSDN フォーラム オペレーター 山本 春海

    2010年8月2日 7:57