ソケットconnect()とbind()


121

connect()bind()システムコールの両方が、ソケットファイル記述子をアドレス(通常はip / portの組み合わせ)に「関連付け」ます。彼らのプロトタイプは次のようなものです-

int connect(int sockfd, const struct sockaddr *addr,
               socklen_t addrlen);

そして

int bind(int sockfd, const struct sockaddr *addr,
            socklen_t addrlen);

2つの呼び出しの正確な違いは何ですか?とき1を使うべきconnect()ときとbind()

具体的には、一部のサンプルサーバークライアントコードで、クライアントが使用してconnect()おり、サーバーがbind()呼び出しを使用していることがわかりました。理由は完全にはわかりませんでした。


19
一文で言えば、バインドはローカルアドレスに、接続はリモートアドレスにです。
SHR 2014年

回答:


230

理解を深めるために、正確にバインドして接続することがどこに当てはまるかを調べてみましょう。

2つのコールの位置付けに加えて、Souravによって明らかにされたように、

bind()はソケットをローカルアドレスに関連付けます[サーバー側がバインドするので、クライアントはそのアドレスを使用してサーバーに接続できます。] connect()は、リモート[サーバー]アドレスに接続するために使用されます。 、connect [read as:connect to server]が使用されます。

特定の役割と対応する実装のために、同じマシン上にクライアント/サーバーがある場合でも、それらを交換して使用することはできません。

さらに、これらの呼び出しをTCP / IPハンドシェイクに関連付けることをお勧めします。

ここに画像の説明を入力してください

したがって、ここにSYNを送信する人は、connect()になります。bind()は通信のエンドポイントを定義するために使用されます。

お役に立てれば!!


1
ありがとう兄貴。この図を使用すると、すべてがすばやく理解できます。udpを使用している場合、ここでの違いは何ですか?
2015

8
accept()<br>は、クライアントからの接続まで<br>ブロックの下に移動する必要があります
tschodt

p2pネットワークのネットワーク内のすべてのノードがバインドを使用する必要があると思いますが、正しいですか?
カピル

46

ワンライナー: bind()自分のアドレスに、connect()リモートアドレスに。

のmanページからの引用 bind()

bind()は、addrによって指定されたアドレスを、ファイル記述子sockfdによって参照されるソケットに割り当てます。addrlenは、addrが指すアドレス構造のサイズをバイト単位で指定します。従来、この操作は「ソケットへの名前の割り当て」と呼ばれています。

そして、同じから connect()

connect()システムコールは、ファイル記述子sockfdによって参照されるソケットをaddrによって指定されたアドレスに接続します。

明確にするために、

  • bind()ソケットをローカルアドレスに関連付けます[これがサーバー側の理由bindであり、クライアントはそのアドレスを使用してサーバーに接続できます。]
  • connect() リモート[サーバー]アドレスへの接続に使用されます。これがクライアント側の理由です。接続[読み取り:サーバーへの接続]が使用されます。

つまり、サーバーとクライアントの両方のプロセスが同じマシンで実行されている場合、それらを交換して使用できますか?
Siddhartha Ghosh 2014年

1
@SiddharthaGhoshいいえ。クライアントとサーバーは同じマシン上にあるかもしれませんが、それでもそれら異なるプロセスですよね?どちらのAPIも独自の目的を果たします。彼らは決してinterchangeable
Sourav Ghosh 2014

この文脈でローカルとリモートは正確に何を意味していますか?
Siddhartha Ghosh 2014年

@SiddharthaGhosh- local>プロセス自体、remote->他のプロセス。
Sourav Ghosh 2014

@SouravGhoshこれは、クライアント側でバインドするポートを指定できないことを意味しますか?
Hengqi Chen、

12

bindは、実行中のプロセスにポートを要求するよう指示します。つまり、自身をポート80にバインドし、着信要求を待機する必要があります。bindを使用すると、プロセスはサーバーになります。接続を使用するときは、すでに使用中のポートに接続するようにプロセスに指示します。プロセスがクライアントになります。違いは重要です。bindは使用されていないポートを要求し(それを要求してサーバーになることができるようにするため)、connectはすでに使用されているポートが必要であるため(それに接続してサーバーと通信できるようにするため)


9

ウィキペディアからhttp://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29

connect():

connect()システムコールは、ファイル記述子で識別されるソケットを、引数リスト内のそのホストのアドレスで指定されたリモートホストに接続します。

特定のタイプのソケットはコネクションレス型であり、最も一般的にはユーザーデータグラムプロトコルソケットです。これらのソケットの場合、connectは特別な意味を持ちます。データを送受信するためのデフォルトのターゲットが指定されたアドレスに設定され、コネクションレス型ソケットでsend()やrecv()などの関数を使用できるようになります。

connect()はエラーコードを表す整数を返します。0は成功を表し、-1はエラーを表します。

練る():

bind()は、ソケットをアドレスに割り当てます。ソケットがsocket()を使用して作成されると、プロトコルファミリのみが指定され、アドレスは割り当てられません。ソケットが他のホストへの接続を受け入れる前に、アドレスとのこの関連付けをbind()システムコールで実行する必要があります。bind()は3つの引数を取ります。

sockfd、バインドを実行するソケットを表す記述子。my_addr、バインドするアドレスを表すsockaddr構造へのポインター。addrlen、sockaddr構造体のサイズを指定するsocklen_tフィールド。Bind()は成功すると0を返し、エラーが発生した場合は-1を返します。

例:1.)Connectの使用

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(){
  int clientSocket;
  char buffer[1024];
  struct sockaddr_in serverAddr;
  socklen_t addr_size;

  /*---- Create the socket. The three arguments are: ----*/
  /* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
  clientSocket = socket(PF_INET, SOCK_STREAM, 0);

  /*---- Configure settings of the server address struct ----*/
  /* Address family = Internet */
  serverAddr.sin_family = AF_INET;
  /* Set port number, using htons function to use proper byte order */
  serverAddr.sin_port = htons(7891);
  /* Set the IP address to desired host to connect to */
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.17");
  /* Set all bits of the padding field to 0 */
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  

  /*---- Connect the socket to the server using the address struct ----*/
  addr_size = sizeof serverAddr;
  connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);

  /*---- Read the message from the server into the buffer ----*/
  recv(clientSocket, buffer, 1024, 0);

  /*---- Print the received message ----*/
  printf("Data received: %s",buffer);   

  return 0;
}

2.)バインドの例:

int main()
{
    struct sockaddr_in source, destination = {};  //two sockets declared as previously
    int sock = 0;
    int datalen = 0;
    int pkt = 0;

    uint8_t *send_buffer, *recv_buffer;

    struct sockaddr_storage fromAddr;   // same as the previous entity struct sockaddr_storage serverStorage;
    unsigned int addrlen;  //in the previous example socklen_t addr_size;
    struct timeval tv;
    tv.tv_sec = 3;  /* 3 Seconds Time-out */
    tv.tv_usec = 0;

    /* creating the socket */         
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
        printf("Failed to create socket\n");

    /*set the socket options*/
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));

    /*Inititalize source to zero*/
    memset(&source, 0, sizeof(source));       //source is an instance of sockaddr_in. Initialization to zero
    /*Inititalize destinaton to zero*/
    memset(&destination, 0, sizeof(destination));


    /*---- Configure settings of the source address struct, WHERE THE PACKET IS COMING FROM ----*/
    /* Address family = Internet */
    source.sin_family = AF_INET;    
    /* Set IP address to localhost */   
    source.sin_addr.s_addr = INADDR_ANY;  //INADDR_ANY = 0.0.0.0
    /* Set port number, using htons function to use proper byte order */
    source.sin_port = htons(7005); 
    /* Set all bits of the padding field to 0 */
    memset(source.sin_zero, '\0', sizeof source.sin_zero); //optional


    /*bind socket to the source WHERE THE PACKET IS COMING FROM*/
    if (bind(sock, (struct sockaddr *) &source, sizeof(source)) < 0) 
        printf("Failed to bind socket");

    /* setting the destination, i.e our OWN IP ADDRESS AND PORT */
    destination.sin_family = AF_INET;                 
    destination.sin_addr.s_addr = inet_addr("127.0.0.1");  
    destination.sin_port = htons(7005); 

    //Creating a Buffer;
    send_buffer=(uint8_t *) malloc(350);
    recv_buffer=(uint8_t *) malloc(250);

    addrlen=sizeof(fromAddr);

    memset((void *) recv_buffer, 0, 250);
    memset((void *) send_buffer, 0, 350);

    sendto(sock, send_buffer, 20, 0,(struct sockaddr *) &destination, sizeof(destination));

    pkt=recvfrom(sock, recv_buffer, 98,0,(struct sockaddr *)&destination, &addrlen);
    if(pkt > 0)
        printf("%u bytes received\n", pkt);
    }

違いが明らかになることを願っています

宣言するソケットのタイプは必要なものに依存することに注意してください。これは非常に重要です


9

私はあなたが考える場合、それはあなたの理解を助けるだろうと思うconnect()listen()カウンターパートとしてではなく、connect()bind()。この理由は、あなたが電話または省略することができるということですbind()、それはめったに前にそれを呼び出すことをお勧めしませんが、どちらかの前に、connect()前にそれを呼び出すために、かlisten()

サーバーとクライアントの観点から考えるのに役立つ場合、それはlisten()前者とconnect()後者の特徴です。bind()どちらでも見つかります-見つかりません-。

サーバーとクライアントが異なるマシン上にあると想定すると、さまざまな機能を理解しやすくなります。

bind()ローカルで動作します。つまり、呼び出されたマシンの接続の終端を要求されたアドレスにバインドし、要求されたポートを割り当てます。これは、そのマシンがクライアントになるかサーバーになるかには関係ありません。connect()クライアントからサーバーへの接続を開始します。つまり、サーバー上の要求されたアドレスとポートに接続します。を使用してどのアドレスとポートに接続するかを知ることができるように、そのサーバーはほぼ確実にのbind()前に呼び出さlisten()れますconnect()

を呼び出さない場合bind()connect()(クライアント)またはlisten()(サーバー)を呼び出すと、ポートとアドレスが暗黙的に割り当てられ、ローカルマシンにバインドされます。ただし、これは両方の副作用であり、目的ではありません。この方法で割り当てられたポートは一時的です。

ここで重要な点は、クライアントはサーバーに接続するため、クライアントをバインドする必要がないため、特定の何かにバインドするのではなく、エフェメラルポートを使用している場合でも、サーバーはクライアントのアドレスとポートを認識します。一方、サーバーはを呼び出さlisten()なくても呼び出すことができますがbind()、そのシナリオでは、割り当てられた一時ポートを発見し、接続したいクライアントにそれを通信する必要があります。

connect()あなたがTCPに興味があるとおっしゃっていると思いますが、これはUDPにも引き継がれます。bind()最初の呼び出しsendto()(UDPはコネクションレス)の前に呼び出さないと、ポートとアドレスが暗黙的に割り当てられバインドされます。バインディングなしでは呼び出せない関数の1つはですrecvfrom()。これは、割り当てられたポートとバインドされたアドレスがなければ、受信するものがない(または、バインディングがないと解釈する方法によっては多すぎる)ため、エラーを返します。


1

長すぎる; 読み取らない:違いは、送信元(ローカル)または宛先アドレス/ポートが設定されているかどうかです。つまり、bind()送信元とconnect()宛先を設定します。TCPまたはUDPに関係なく。

bind()

bind()ソケットのローカル(ソース)アドレスを設定します。これは、パケットが受信されるアドレスです。ソケットによって送信されたパケットはこれを送信元アドレスとして運ぶため、他のホストはそのパケットをどこに送り返すかを知っています。

受信が不要な場合、ソケットの送信元アドレスは役に立ちません。TCPなどのプロトコルでは、1つ以上のパケットが到着したときに確認(つまり確認)を宛先ホストが送信するため、適切に送信するために受信を有効にする必要があります。

connect()

  • TCPには「接続済み」状態があります。connect()TCPコードをトリガーして、反対側への接続を確立しようとします。
  • UDPには「接続済み」状態はありません。connect()アドレスが指定されていない場合にのみ、パケットが送信されるデフォルトのアドレスを設定します。ときにconnect()使用されていない、sendto()またはsendmsg()宛先アドレスを含む使用する必要があります。

ときにconnect()何のアドレスがバインドされていないか、送信機能が呼び出され、そして、Linuxは自動的にランダムなポートにソケットをバインドします。技術的な詳細については、inet_autobind()Linuxカーネルのソースコードをご覧ください。

サイドノート

  • listen() TCPのみです。
  • AF_INETのファミリー、ソケットの送信元または宛先アドレス(struct sockaddr_in)(参照IPアドレスで構成されているIPヘッダを(参照)、およびTCPまたはUDPポートTCPおよびUDPのヘッダ)。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.