重要なのは、コンピューター内のすべてが単なるバイトの配列(または、ワード、またはダブルワード)であることを理解する必要があるということです。
ZEN MASTER MustARDは机に座って、一見ランダムなキャラクターの複雑なパターンを見つめているモニターを見つめています。学生が近づいています。
学生:マスター?中断してもいいですか?
禅マスターマスタード:あなたはあなた自身の質問に答えました、私の息子。
S:なに?
ZMM:私を邪魔することについてあなたの質問をすることによって、あなたは私を邪魔しました。
S:ああ、ごめんなさい。さまざまなサイズの構造物を場所ごとに移動することについて質問があります。
ZMM:それが本当なら、あなたはそのようなことで優れているマスターに相談するべきです。レーダーの追跡などの大きな金属構造物を場所から場所へ移動するのに優れた知識を持っているMasterDotPuftを訪問することをお勧めします。マスターDotPuftは、羽の重さのひずみゲージのわずかな要素を鳩の息の力で動かすこともできます。右に曲がり、ハイベイのドアに着いたら左に曲がります。そこにはマスターDotPuftが住んでいます。
S:いいえ、私はコンピュータのメモリ内の場所から場所へとさまざまなサイズの大きな構造物を移動することを意味します。
ZMM:必要に応じて、その取り組みを支援する場合があります。問題を説明してください。
S:具体的には、いくつかの異なるタイプの構造体を受け入れたいAC関数があります(それらは異なるタイプのパケットを表します)。したがって、構造体パケットはvoid*として関数に渡されます。しかし、タイプを知らなければ、私はそれらをキャストすることはできませんし、実際には何もできません。socket.hのsento()がまさにそれを行うので、これが解決可能な問題であることを私は知っています:
ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
sendtoは次のように呼び出されます。
sendto(socketAddress, &myPacket, sizeof(myPacket), Other args....);
ZMM:Zen Master MANTARにあなたの問題を説明しましたか??
S:ええ、彼は「それはただのポインターです。Cのすべてがポインターです」と言いました。私が彼に説明を求めたとき、彼は「ボク、ボク、私のオフィスから地獄を出して」と言った。
ZMM:本当に、あなたはマスターと話しました。これはあなたを助けませんでしたか?
S:ええと、えー、いや。それから私は禅マスターマックスに尋ねました。
ZMM:賢いのは彼です。あなたへの彼のアドバイスは役に立ちましたか?
S:いいえ。sendto()について聞いたところ、彼は拳を空中で渦巻かせていました。単なるバイトの配列です。」
ZMM:確かに、ZenMasterMaxにはタウがあります。
S:ええ、彼はタウを持っていますが、void *型の関数の引数をどのように処理しますか?
ZMM:学ぶには、まず学習をやめる必要があります。重要なのは、コンピューター内のすべてが単なるバイトの配列(または、ワード、またはダブルワード)であることを理解する必要があるということです。バッファの先頭とバッファの長さへのポインタがわかれば、バッファに配置されているデータの種類を知らなくても、どこにでも送信できます。
S:わかりました。
ZMM:人間が読めるテキストの文字列について考えてみましょう。「あなたは雲を突き刺す塔を計画していますか?最初に謙虚さの基礎を築いてください。」長さは82バイトです。または、おそらく、邪悪なUnicodeが使用されている場合は164です。Unicodeの嘘から身を守ってください!このテキストをsendto()に送信するには、次のように、文字列を含むバッファーの先頭へのポインターと、バッファーの長さを指定します。
char characterBuffer[300]; // 300 bytes
strcpy(characterBuffer, "You plan a tower that will pierce the clouds? Lay first the foundation of humility.");
// note that sizeof(characterBuffer) evaluates to 300 bytes.
sendto(socketAddress, &characterBuffer, sizeof(characterBuffer));
ZMM:文字バッファのバイト数はコンパイラによって自動的に計算されることに注意してください。変数タイプが占めるバイト数は、「size_t
」と呼ばれるタイプです。long
タイプ「 」または「 」と同等である可能性unsinged int
がありますが、コンパイラに依存します。
S:ええと、構造体を送信したい場合はどうなりますか?
ZMM:では、構造体を送信しましょう。
struct
{
int integerField; // 4 bytes
char characterField[300]; // 300 bytes
float floatField; // 4 bytes
} myStruct;
myStruct.integerField = 8765309;
strcpy(myStruct.characterField, "Jenny, I got your number.");
myStruct.floatField = 876.5309;
// sizeof(myStruct) evaluates to 4 + 300 + 4 = 308 bytes
sendto(socketAddress, &myStruct, sizeof(myStruct);
S:ええ、それはTCP/IPソケットを介して物事を送信するのに優れています。しかし、受信機能が悪いのはどうですか?文字配列と構造体のどちらを送信しているかをどのように判断できますか?
ZMM:1つの方法は、送信される可能性のあるさまざまなタイプのデータを列挙してから、そのタイプのデータをデータと一緒に送信することです。Zen Mastersは、これを「メタデータ」、つまり「データに関するデータ」と呼んでいます。受信関数は、メタデータを調べて送信されているデータの種類(struct、float、character array)を判別し、この情報を使用してデータを元のタイプにキャストし直す必要があります。まず、送信機能について考えてみましょう。
enum
{
INTEGER_IN_THE_PACKET =0 ,
STRING_IN_THE_PACKET =1,
STRUCT_IN_THE_PACKET=2
} typeBeingSent;
struct
{
typeBeingSent dataType;
char data[4096];
} Packet_struct;
Packet_struct myPacket;
myPacket.dataType = STRING_IN_THE_PACKET;
strcpy(myPacket.data, "Nothing great is ever achieved without much enduring.");
sendto(socketAddress, myPacket, sizeof(Packet_struct);
myPacket.dataType = STRUCT_IN_THE_PACKET;
memcpy(myPacket.data, (void*)&myStruct, sizeof(myStruct);
sendto(socketAddress, myPacket, sizeof(Packet_struct);
S:大丈夫です。
ZMM:では、受信機能と一緒に歩きます。送信されたデータのタイプを照会し、そのタイプで宣言された変数にデータをコピーする必要があります。許してください、でもそのrecvfrom()
機能の正確さを忘れてしまいました。
char[300] receivedString;
struct myStruct receivedStruct;
recvfrom(socketDescriptor, myPacket, sizeof(myPacket);
switch(myPacket.dataType)
{
case STRING_IN_THE_PACKET:
// note the cast of the void* data into type "character pointer"
&receivedString[0] = (char*)&myPacket.data;
printf("The string in the packet was \"%s\".\n", receivedString);
break;
case STRUCT_IN_THE_PACKET:
// note the case of the void* into type "pointer to myStruct"
memcpy(receivedStruct, (struct myStruct *)&myPacket.data, sizeof(receivedStruct));
break;
}
ZMM:あなたは悟りを達成しましたか?まず、送信するデータのサイズ(バイト数)をコンパイラーに要求しますsendto()
。元のデータのタイプも一緒に送信されます。次に、レシーバーは元のデータのタイプを照会し、それを使用して、「ポインターからボイド」(一般的なポインター)から元のデータのタイプ(int、char []、構造体、等。)
S:まあ、やってみます。
ZMM:安心してください。