1

コマンドを送信し、IrDA ソケット通信を使用してデバイスから応答を読み取る必要があります。コマンドをパッケージ化するのはかなり簡単ですが、予想される応答のサイズを決定することはできません。たとえば、コマンド "GET_ERRORS" を実行すると、デバイスは0 から n\nまでのデータを、それぞれ最大 80 バイトの区切り行で返し ます。投稿*ここを読みましたが、実際のデータ ブロックの前にある *** ヘッダー *がデバイスから提供されません。

[編集]
GET_ERRORS コマンドからの典型的な応答は次のとおりです (読みやすくするために簡略化されています)。

Date       Time     Fault
10/12/2000 02:00:00 3f46
10/12/2000 02:00:00 bcf5
10/12/2000 02:00:00 1312
10/12/2000 02:00:00 a334
10/12/2000 02:00:00 b212
10/12/2000 02:00:00 b212
10/12/2000 02:00:00 c43a
%

この例 (SO の投稿HEREから) は、返されるデータの長さがわかっている場合にうまく機能します。

int recv_all(int sockfd, void *buf, size_t len, int flags)
{
    size_t toread = len;
    char  *bufptr = (char*) buf;

    while (toread > 0)
    {
        ssize_t rsz = recv(sockfd, bufptr, toread, flags);
        if (rsz <= 0)
            return rsz;  /* Error or other end closed cnnection */

        toread -= rsz;  /* Read less next time */
        bufptr += rsz;  /* Next buffer position to read into */
    }

    return len;
}

しかし、不明な量のデータを受け取りたい場合、私が知っている唯一のことは、大きなバッファーを宣言してから、次のようなものに渡すことです。

int IrdaCommReceive(int irdaCommSocket, void* largeBuf, size_t len, int* rcvd)
{
    char *bufptr = (char *)largeBuf;

    int bytesRcvd = recv(irdaCommSocket, bufptr, len, 0);

    if (bytesRcvd < 0) return WSAGetLastError();
    *rcvd = bytesRcvd;

    return 0;
}

不確定なサイズのソケット データの受信関数を作成するより良い方法はありますか?

4

3 に答える 3

5

ソケット メッセージは、通信の完全性を保証する何らかの方法でフレーム化する必要があります。たとえば、UDP データグラム ソケットは自己完結型のメッセージを送受信します。データはメッセージの境界をまたがることはできません。TCP ストリーム ソケットにはその制限がないため、代わりに、メッセージの長さを説明するヘッダーまたはメッセージ データに表示されない一意のターミネータを使用して、論理メッセージを区切る必要があります。IrDA ソケットも例外ではありません。

応答の実際のデータGET_ERRORSやそのコードは表示されていませんが、応答メッセージの前にヘッダーがないと言っているので、2 つの可能性しかありません。

  1. トランスポート レベルでのメッセージ フレーミング。タイプを使用して IrDA ソケットを作成している場合、これは処理されますSOCK_DGRAMrecv()小さすぎるバッファを使用すると、メッセージは破棄され、エラーが発生しWSAEMSGSIZEます。

  2. アプリケーションレベルでのメッセージ区切り。タイプを使用して IrDA ソケットを作成している場合は、これを自分で処理する必要がありますSOCK_STREAM。任意のバッファーを提供recv()し、要求されたサイズまで、使用可能なデータをすべて入力します。recv()探しているデータが見つかるまで、必要に応じて続行して、さらにデータを受け取るためにもう一度呼び出すだけです。

IrDA は一般的にソケットで使用されるため、後者を想定しています。IrDA ベースのGET_ERRORSコマンドに関するオンライン ドキュメントを見つけることができません (そのようなドキュメントはありますか?)。0 ~ n 行を送信している可能性がありますが、最後の行の長さは 0 または同等であるに違いありません。その場合、recv()そのターミネータを受信するまでループで呼び出すだけです。

于 2013-09-24T19:39:42.570 に答える
1

このようなことを試すことができます。

コマンドをデバイスに送信します。次に、ループ内でソケットに対して epoll() または select() を呼び出して、ソケットがデータを受信する準備ができているかどうかをテストします。select() が返され、ソケットが読み取り可能なデータを持っていることを示している場合は、行の終わりを示す \n が受信されるまで recv() を繰り返し呼び出します。その recv_all() はその目的には問題ありません。必要に応じてその行を処理し、ループの先頭に戻ります。

select() でタイムアウトを使用して、プログラムが停止して何か他のことを実行できるようにしたり、デバイスからデータが来なくなったことを判断したりできます。タイムアウト パラメータを変更する select の実装は、ここで役立ちます。

もちろん、これは select() が Windows の irda ソケットで動作することを前提としています...

于 2013-09-24T20:33:03.270 に答える