GNU/Linux >> Linux の 問題 >  >> Linux

bind() を呼び出すときに sockaddr_in を sockaddr にキャストするのはなぜですか?

いいえ、単なる慣例ではありません。

sockaddr sockaddr_in は、あらゆる種類のソケット操作の汎用記述子です。 IP ベースの通信 (IIRC、「in」は「InterNet」を表します) に固有の構造体です。私の知る限り、これは一種の「ポリモーフィズム」です:bind() 関数は struct sockaddr * を取るふりをします 、しかし実際には、適切なタイプの構造体が渡されると想定します。私。 e.最初の引数として指定したソケットのタイプに対応するもの。


この質問に非常に関連するかどうかはわかりませんが、C にあまり時間を費やしていない多くの人々として、型キャストをより理解しやすくする追加情報を提供したいと思います。 そのようなタイプカーストを見ると混乱します。

macOS を使用しています であるため、システムのヘッダー ファイルに基づいた例を使用しています。

struct sockaddr は次のように定義されます:

struct sockaddr {
    __uint8_t       sa_len;         /* total length */
    sa_family_t     sa_family;      /* [XSI] address family */
    char            sa_data[14];    /* [XSI] addr value (actually larger) */
};

struct sockaddr_in は次のように定義されます:

struct sockaddr_in {
    __uint8_t       sin_len;
    sa_family_t     sin_family;
    in_port_t       sin_port;
    struct  in_addr sin_addr;
    char            sin_zero[8];
};

非常に基本的なことから始めて、ポインターにはアドレスが含まれているだけです。だから struct sockaddr *struct sockaddr_in * ほとんど同じです。どちらもアドレスを保存するだけです。関連する唯一の違いは、コンパイラがオブジェクトを処理する方法です。

(struct sockaddr *) &name と言うと 、コンパイラをだまして、このアドレスが struct sockaddr を指していると伝えているだけです タイプしてください。

ポインタが場所 1000 を指しているとしましょう . struct sockaddr * の場合 このアドレスを保存すると、1000 からのメモリが考慮されます sizeof(struct sockaddr)まで 構造定義に従ってメンバーを所有します。 struct sockaddr_in * の場合 1000 からメモリと見なされる同じアドレスを保存します sizeof(struct sockaddr_in) へ .

そのポインタを型キャストすると、sizeof(struct sockaddr) までの同じバイト シーケンスが考慮されます。 .

struct sockaddr *a = &name; // consider &name = 1000

a->sa_len にアクセスすると 、コンパイラは場所 1000 からアクセスします sizeof(__uint8_t)sockaddr_in の場合と同じバイトサイズです .したがって、これは同じバイト シーケンスにアクセスする必要があります。

sa_family も同じパターン .

その後、struct sockaddr に 14 バイトの文字配列があります in_port_t sin_port からのデータを保存します (typedef 'd 16 ビット符号なし整数 =2 バイト)、struct in_addr sin_addr (単に 32 ビットの ipv4 アドレス =4 バイト) および char sin_zero[8] (8 バイト)。これら 3 つを合計すると 14 バイトになります。

現在、これら 3 つはこの 14 バイトの文字配列に格納されており、適切なインデックスにアクセスして再度型キャストすることで、これら 3 つのいずれかにアクセスできます。

user529758 の回答では、これを行う理由が既に説明されています。


これは、bind が IP ソケット以外のタイプのソケット (たとえば、タイプとして sockaddr_un を持つ Unix ドメイン ソケット) をバインドできるためです。 AF_INET ソケットのアドレスには、アドレスとしてホストとポートがありますが、AF_UNIX ソケットにはファイルシステム パスがあります。


Linux
  1. バインド マウントがマウント名前空間の外に表示されるのはなぜですか?

  2. sudo vi <filename> を実行しても構文が強調表示されないのはなぜですか?

  3. 十分な空きメモリが残っているときにスワップが使用されるのはなぜですか?

  1. libvirt_typeがKVMの場合、OpenStackがハイパーバイザータイプをQEMUとして報告するのはなぜですか?

  2. 起動可能なLinuxUSBスティックを作成するときに同期が非常に重要なのはなぜですか?

  3. 「vi」エディタで編集すると、iノードの値が変わるのはなぜですか。

  1. Mvを呼び出すときにディレクトリパスを含める簡単な方法??

  2. 引用符を使用すると、なぜ単一の円記号が表示されるのですか?

  3. このシェル パイプラインが終了するのはなぜですか?