soket menghubungkan () vs mengikat ()

121

Keduanya connect()dan bind()panggilan sistem 'mengasosiasikan' deskriptor file soket ke sebuah alamat (biasanya kombinasi ip / port). Prototipe mereka seperti: -

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

dan

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

Apa perbedaan persis antara 2 panggilan? Kapan sebaiknya digunakan connect()dan kapan bind()?

Secara khusus, dalam beberapa kode klien server sampel, ditemukan bahwa klien menggunakan connect()dan server menggunakan bind()panggilan. Alasannya tidak sepenuhnya jelas bagi saya.

Siddhartha Ghosh
sumber
19
Dalam satu kalimat: mengikat ke alamat lokal, menghubungkan ke alamat jarak jauh.
SHR

Jawaban:

230

Untuk membuat pemahaman lebih baik, mari kita cari tahu di mana tepatnya mengikat dan terhubung menjadi gambar,

Selanjutnya untuk memposisikan dua panggilan, seperti yang dijelaskan oleh Sourav,

bind () mengasosiasikan soket dengan alamat lokalnya [itulah sebabnya sisi server mengikat, sehingga klien dapat menggunakan alamat itu untuk terhubung ke server.] connect () digunakan untuk terhubung ke alamat [server] jarak jauh, itulah mengapa sisi klien , hubungkan [baca sebagai: sambungkan ke server] digunakan.

Kami tidak dapat menggunakannya secara bergantian (bahkan ketika kami memiliki klien / server pada mesin yang sama) karena peran khusus dan implementasi yang sesuai.

Saya selanjutnya akan merekomendasikan untuk menghubungkan panggilan ini jabat tangan TCP / IP.

masukkan deskripsi gambar di sini

Jadi, siapa yang akan mengirim SYN ke sini, itu akan terhubung (). Sedangkan bind () digunakan untuk mendefinisikan titik akhir komunikasi.

Semoga ini membantu!!

Jain Rach
sumber
1
terima kasih bro. Dengan diagram semuanya bisa tidak tahan dengan cepat. Bisakah Anda ceritakan apa bedanya di sini, jika kami menggunakan udp?
apm
8
accept () <br> harus dipindahkan di bawah blok <br> hingga koneksi dari klien
tschodt
saya pikir semua node dalam jaringan di jaringan P2P harus menggunakan bind, apakah saya benar?
kapil
46

Satu baris: bind() ke alamat sendiri, connect()ke alamat remote.

Mengutip dari halaman manual bind()

bind () memberikan alamat yang ditentukan oleh addr ke soket yang dirujuk oleh deskriptor file sockfd. addrlen menentukan ukuran, dalam byte, dari struktur alamat yang ditunjukkan oleh addr. Secara tradisional, operasi ini disebut "menugaskan nama ke soket".

dan, dari yang sama untuk connect()

Panggilan sistem connect () menghubungkan soket yang dirujuk oleh deskriptor file sockfd ke alamat yang ditentukan oleh addr.

Untuk memperjelas,

  • bind()mengaitkan soket dengan alamat lokalnya [itulah sebabnya sisi server binds, sehingga klien dapat menggunakan alamat itu untuk menyambung ke server.]
  • connect() digunakan untuk menghubungkan ke alamat remote [server], oleh karena itu di sisi klien, digunakan koneksi [baca sebagai: sambungkan ke server].
Sourav Ghosh
sumber
Jadi, katakanlah, jika proses server dan klien berjalan pada mesin yang sama, dapatkah keduanya digunakan secara bergantian?
Siddhartha Ghosh
1
@SiddharthaGhosh No. mungkin klien dan server berada di mesin yang sama, namun tetap saja mereka adalah proses yang berbeda, kan? Kedua API melayani fungsinya sendiri. Mereka tidak pernahinterchangeable
Sourav Ghosh
Apa sebenarnya yang dimaksud dengan lokal dan remote dalam konteks ini?
Siddhartha Ghosh
@SiddharthaGhosh local-> proses itu sendiri, remote-> proses lainnya.
Sourav Ghosh
@SouravGhosh jadi ini berarti saya tidak dapat menentukan port yang akan diikat di sisi klien?
Hengqi Chen
12

bind memberi tahu proses yang sedang berjalan untuk mengklaim port. yaitu, ia harus mengikat dirinya sendiri ke port 80 dan mendengarkan permintaan masuk. dengan bind, proses Anda menjadi server. ketika Anda menggunakan connect, Anda memberi tahu proses Anda untuk terhubung ke port yang SUDAH digunakan. proses Anda menjadi klien. perbedaannya penting: bind menginginkan port yang tidak digunakan (sehingga dapat mengklaimnya dan menjadi server), dan menghubungkan menginginkan port yang sudah digunakan (sehingga dapat terhubung dan berbicara ke server)

Philipp Murry
sumber
9

Dari Wikipedia http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29

Menghubung():

Panggilan sistem connect () menghubungkan soket, yang diidentifikasi oleh deskriptor filenya, ke host jarak jauh yang ditentukan oleh alamat host tersebut dalam daftar argumen.

Jenis soket tertentu tidak memiliki koneksi, soket protokol datagram pengguna yang paling umum. Untuk soket ini, hubungkan memiliki arti khusus: target default untuk mengirim dan menerima data diatur ke alamat yang diberikan, memungkinkan penggunaan fungsi seperti send () dan recv () pada soket tanpa koneksi.

connect () mengembalikan integer yang mewakili kode kesalahan: 0 mewakili sukses, sedangkan -1 mewakili kesalahan.

mengikat():

bind () memberikan soket ke alamat. Ketika soket dibuat menggunakan soket (), itu hanya diberikan keluarga protokol, tetapi tidak diberi alamat. Asosiasi dengan alamat ini harus dilakukan dengan panggilan sistem bind () sebelum soket dapat menerima koneksi ke host lain. bind () membutuhkan tiga argumen:

sockfd, deskriptor yang mewakili soket untuk melakukan pengikatan. my_addr, penunjuk ke struktur sockaddr yang mewakili alamat yang akan diikat. addrlen, bidang socklen_t yang menentukan ukuran struktur sockaddr. Bind () mengembalikan 0 jika berhasil dan -1 jika terjadi kesalahan.

Contoh: 1.) Menggunakan 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.) Bind Contoh:

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);
    }

Saya harap itu menjelaskan perbedaannya

Harap dicatat bahwa jenis soket yang Anda nyatakan akan bergantung pada apa yang Anda butuhkan, ini sangat penting

Khan
sumber
9

Saya pikir itu akan membantu pemahaman Anda jika Anda memikirkan connect()dan listen()sebagai rekan, daripada connect()dan bind(). Alasan untuk ini adalah Anda dapat memanggil atau menghilangkan bind()sebelumnya, meskipun jarang merupakan ide yang baik untuk memanggilnya sebelumnya connect(), atau tidak memanggilnya sebelumnya listen().

Jika membantu untuk berpikir dalam kerangka server dan klien, itulah listen()ciri khas yang pertama, dan connect()yang terakhir. bind()dapat ditemukan - atau tidak ditemukan - di keduanya.

Jika kita mengasumsikan server dan klien kita berada di mesin yang berbeda, akan lebih mudah untuk memahami berbagai fungsi.

bind()bertindak secara lokal, yaitu mengikat akhir koneksi pada mesin yang dipanggil, ke alamat yang diminta dan memberikan port yang diminta kepada Anda. Itu melakukan itu terlepas dari apakah mesin itu akan menjadi klien atau server. connect()memulai koneksi ke server, yang berarti menghubungkan ke alamat dan port yang diminta di server, dari klien. Server itu hampir pasti akan menelepon bind()sebelumnya listen(), agar Anda dapat mengetahui alamat dan port mana yang akan dihubungkan dengannya dengan menggunakan connect().

Jika Anda tidak menelepon bind(), port dan alamat akan secara implisit ditetapkan dan terikat pada mesin lokal untuk Anda saat Anda memanggil connect()(klien) atau listen()(server). Namun, itu efek samping dari keduanya, bukan tujuan mereka. Port yang ditetapkan dengan cara ini bersifat sementara.

Poin penting di sini adalah bahwa klien tidak perlu terikat, karena klien terhubung ke server, sehingga server akan mengetahui alamat dan port klien meskipun Anda menggunakan port sementara, daripada mengikat ke sesuatu yang spesifik. Di sisi lain, meskipun server dapat menelepon listen()tanpa menelepon bind(), dalam skenario itu mereka perlu menemukan port sementara yang ditetapkan, dan mengomunikasikannya ke klien mana pun yang ingin disambungkan ke sana.

Saya berasumsi ketika Anda menyebutkan connect()Anda tertarik dengan TCP, tetapi ini juga membawa ke UDP, di mana tidak menelepon bind()sebelum yang pertama sendto()(UDP adalah koneksi-kurang) juga menyebabkan port dan alamat secara implisit ditetapkan dan diikat. Salah satu fungsi yang tidak dapat Anda panggil tanpa pengikatan adalah recvfrom(), yang akan mengembalikan kesalahan, karena tanpa port yang ditetapkan dan alamat yang terikat, tidak ada yang bisa diterima (atau terlalu banyak, tergantung pada bagaimana Anda menafsirkan tidak adanya pengikatan).

pjcard
sumber
1

Terlalu panjang; Jangan Baca: Perbedaannya adalah apakah sumber (lokal) atau alamat / port tujuan sedang disetel. Singkatnya, bind()atur sumber dan connect()tentukan tujuan. Terlepas dari TCP atau UDP.

bind()

bind()atur alamat (sumber) lokal soket. Ini adalah alamat dimana paket diterima. Paket yang dikirim oleh soket membawa ini sebagai alamat sumber, sehingga host lain akan tahu ke mana harus mengirim kembali paketnya.

Jika menerima tidak diperlukan alamat sumber soket tidak berguna. Protokol seperti TCP mengharuskan penerimaan diaktifkan untuk mengirim dengan benar, karena host tujuan mengirim kembali konfirmasi ketika satu atau lebih paket telah tiba (yaitu pengakuan).

connect()

  • TCP memiliki status "terhubung". connect()memicu kode TCP untuk mencoba membuat sambungan ke sisi lain.
  • UDP tidak memiliki status "terhubung". connect()hanya mengatur alamat default ke mana paket dikirim ketika tidak ada alamat yang ditentukan. Kapan connect()tidak digunakan, sendto()atau sendmsg()harus digunakan yang berisi alamat tujuan.

Ketika connect()atau fungsi kirim dipanggil, dan tidak ada alamat yang terikat, Linux secara otomatis mengikat soket ke port acak. Untuk detail teknis, lihat di inet_autobind()kode sumber kernel Linux.

Catatan sampingan

  • listen() hanya TCP.
  • Dalam keluarga AF_INET , sumber soket atau alamat tujuan ( struct sockaddr_in) terdiri dari alamat IP (lihat header IP ), dan port TCP atau UDP (lihat header TCP dan UDP ).
Ricardo Biehl Pasquali
sumber