CのTCPソケット接続を介してBinderクラスにメッセージを送信したい。write(を使用して、この接続を介して要求タイプ(char *)、IPアドレス(int)、argTypes(int配列)などを渡す必要があります。 ) 方法。すべての情報を1つのメッセージで送信するための最良の方法は何ですか?
3 に答える
1 回の読み取り/書き込み操作ですべてのデータを送受信できるという保証はありません。要因が多すぎると、品質/パケットサイズ/接続安定性などに影響を与える可能性があります。
この質問/回答はそれを説明しています。
ここにいくつかのC の例があります。C でのソケット プログラミング
の適切な説明。TCP/IP
の簡単な概要。
さまざまな種類のメッセージの送信について:
サーバーアプリから送信されたデータは、クライアントアプリによって受信され、クライアントアプリはこのデータを好きなように解釈できます。
1 回の書き込みと 1 回の読み取りでデータを送受信する場合は、データグラム ソケットを使用する必要があります。write
データグラム ソケットはコネクションレスであるため、 /は使用できませんread
。代わりに、sendto
/recvfrom
またはsendmsg
/を使用しますrecvmsg
。データグラム ソケットは信頼できないため、独自のプロトコルを実装して、順不同のデータ配信とデータ損失を許容する必要があります。
データグラム ソケットの信頼性の低い性質に対処したくない場合は、ストリーム ソケットが必要です。ストリームソケットが接続されているため、送信データは保証され、正常です。送信するデータが常に同じサイズである場合は、呼び出しにブロッキング モードを使用してから呼び出しを渡すことで、データグラムを模倣できsend
ます。MSG_WAITALL
recv
#define MY_MSG_SIZE 9876
int my_msg_send (int sock, const void *msg) {
int r, sent = 0;
do {
r = send(sock, (const char *)msg + sent, MY_MSG_SIZE - sent,
MSG_NOSIGNAL);
if (r <= 0) {
if (r < 0 && errno == EINTR) continue;
break;
}
sent += r;
} while (sent < MY_MSG_SIZE);
if (sent) return sent;
return r;
}
int my_msg_recv (int sock, void *msg) {
int r, rcvd = 0;
do {
r = recv(sock, (char *)msg + rcvd, MY_MSG_SIZE - rcvd, MSG_WAITALL);
if (r <= 0) {
if (r < 0 && errno == EINTR) continue;
break;
}
rcvd += r;
while (rcvd < MY_MSG_SIZE);
if (rcvd) return rcvd;
return r;
}
ソフトウェアは特定のエラー ケースに対処する必要があることに注意してください。の場合EINTR
、I/O 操作を再試行する必要があります。その他のエラーについては、データの配信または取得が不完全である可能性があります。do
しかし、一般に、ソケットをブロックする場合、上記の-while
ループの反復は 1 回だけであると予想されます。
メッセージが常に同じサイズではない場合、メッセージをフレームに収める方法が必要です。フレーム化されたメッセージとは、メッセージの開始と終了を検出する方法が必要であることを意味します。おそらく、ストリーミング ソケットを介してメッセージをフレーム化する最も簡単な方法は、メッセージの前にそのサイズを付けることです。次に、受信者は最初にサイズを読み取り、次にメッセージの残りを読み取ります。my_msg_send
サンプルコードを簡単に適応させて、それを行うことができるはずmy_msg_recv
です。
最後に、メッセージ自体の問題があります。メッセージが常に同じサイズではない場合、メッセージ内に 1 つ以上の可変長レコードがある可能性があります。例としては、値の配列や文字列があります。送信者と受信者の両方がレコードの順序に同意する場合、各可変長レコードの前にその長さを付ければ十分です。メッセージの構造が次のようになっているとします。
struct my_data {
const char *name;
int address;
int *types;
int number_of_types;
};
struct my_data
次に、次のようなインスタンスを表すことができます。
NAME_LEN : 4 bytes
NAME : NAME_LEN bytes
ADDRESS : 4 bytes
TYPES_LEN : 4 bytes
TYPES : TYPES_LEN * 4 bytes
NAME_LEN
から取得されstrlen(msg->name)
、TYPES_LEN
からその値を取得しますmsg->number_of_types
。メッセージを送信すると、上記のメッセージの合計の長さが前に表示されます。
長さを表すために 32 ビット量を使用してきましたが、これはおそらく目的には十分です。ソケットを介して数値を送信する場合、送信者と受信者は数値のバイト順について合意する必要があります。つまり、数値 1 が として表される0.0.0.1
か、 として表されるかということ1.0.0.0
です。これは通常、前者を使用するネットワーク バイト オーダーを使用して処理できます。htonl
ソケット ヘッダー ファイルは、32 ビット値をホストのネイティブ バイト オーダーからネットワーク バイト オーダーに変換するマクロを提供します。これは、たとえば に値を格納するときに使用されますNAME_LEN
。受信者は対応するマクロを使用しますntohl
送信された値をホストが使用する表現に戻します。もちろん、ホストのネイティブ バイト オーダーがネットワーク バイト オーダーとすでに一致している場合、マクロはノーオペレーションになる可能性があります。これらのマクロの使用は、異種環境でデータを送受信する場合に特に重要です。これは、送信側と受信側でホストのバイト順序が異なる場合があるためです。
データが関連している場合は、別のヘッダーで構造体を作成し、それをクライアント コードとサーバー コードの両方で使用して、この構造体の変数を送信できます。関係がない場合、なぜそれらを 1 つのメッセージとして送信する必要があるのかわかりません。