soket bağlantısı () vs bind ()


121

Hem connect()ve hem de bind()sistem çağrıları, soket dosya tanımlayıcısını bir adresle (tipik olarak bir ip / bağlantı noktası kombinasyonu) 'ilişkilendirir'. Prototipleri şöyle: -

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

ve

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

2 çağrı arasındaki tam fark nedir? Ne zaman connect()ve ne zaman kullanılmalı bind()?

Özellikle, bazı örnek sunucu istemci kodlarında, istemcinin aramayı kullandığı connect()ve sunucunun bind()aramayı kullandığı bulundu . Sebep benim için tam olarak net değildi.


19
Bir cümleyle: bağlama yerel adrese, bağlantı uzak adrese.
SHR

Yanıtlar:


230

Anlamayı daha iyi hale getirmek için, resmin tam olarak nerede bağlandığını ve bağlandığını bulalım,

Sourav tarafından açıklandığı gibi, iki çağrının konumlandırılmasına ek olarak,

bind () soketi yerel adresiyle ilişkilendirir [bu nedenle sunucu tarafı bağlanır, böylece istemciler bu adresi sunucuya bağlanmak için kullanabilir.] connect () uzak bir [sunucu] adresine bağlanmak için kullanılır, bu yüzden istemci tarafı bağlan [farklı oku: sunucuya bağlan] kullanılır.

Belirli roller ve ilgili uygulama nedeniyle bunları birbirinin yerine kullanamayız (aynı makinede istemci / sunucu olsa bile).

Bu aramaları TCP / IP anlaşması arasında ilişkilendirmeyi de tavsiye edeceğim.

görüntü açıklamasını buraya girin

Öyleyse, buraya kim SYN gönderecek, connect () olacaktır. Bind () iletişim uç noktasını tanımlamak için kullanılır.

Bu yardımcı olur umarım!!


1
sağ ol, kanka. Diyagram ile her şey hızlı bir şekilde anlaşılabilir. Buradaki farkın ne olduğunu söyleyebilir misiniz, eğer udp kullanıyorsak?
apm

8
kabul () <br> istemciden bağlantıya kadar <br> bloğunun altına taşınmalı
tschodt

p2p ağındaki bir ağdaki tüm düğümlerin bind kullanması gerektiğini düşünüyorum, doğru muyum?
kapil

46

Tek satır: bind() kendi adrese, connect()uzak adrese.

Man sayfasından alıntı bind()

bind (), adres tarafından belirtilen adresi sockfd dosya tanımlayıcısı tarafından belirtilen sokete atar. addrlen, adres tarafından gösterilen adres yapısının bayt cinsinden boyutunu belirtir. Geleneksel olarak, bu işleme "bir sokete bir ad atama" denir.

ve aynısından connect()

Connect () sistem çağrısı, sockfd dosya tanımlayıcısı tarafından belirtilen soketi adres tarafından belirtilen adrese bağlar.

Netleştirmek için,

  • bind()soketi yerel adresiyle ilişkilendirir [bu bindnedenle, istemciler sunucuya bağlanmak için bu adresi kullanabilir.]
  • connect() uzak bir [sunucu] adresine bağlanmak için kullanılır, bu nedenle istemci tarafı, bağlan [farklı oku: sunucuya bağlan] kullanılır.

Öyleyse, diyelim ki hem sunucu hem de istemci süreci aynı makinede çalışıyorsa, birbirlerinin yerine kullanılabilirler mi?
Siddhartha Ghosh

1
@SiddharthaGhosh Hayır. Belki istemci ve sunucu aynı makinede, ama yine de farklı süreçler, değil mi? Her iki API de kendi amacına hizmet eder. Onlar aslainterchangeable
Sourav Ghosh

Bu bağlamda yerel ve uzak ile tam olarak ne kastedilmektedir?
Siddhartha Ghosh

@SiddharthaGhosh local-> sürecin kendisi, remote-> diğer süreç.
Sourav Ghosh

@SouravGhosh, yani bu, istemci tarafında bağlanmak için bir bağlantı noktası belirleyemeyeceğim anlamına mı geliyor?
Hengqi Chen

12

bind, çalışan işleme bir bağlantı noktası talep etmesini söyler. yani, kendisini 80 numaralı bağlantı noktasına bağlamalı ve gelen istekleri dinlemelidir. bind ile süreciniz bir sunucu haline gelir. connect kullandığınızda, işleminize ZATEN kullanımda olan bir bağlantı noktasına bağlanmasını söylersiniz. süreciniz bir müşteri haline gelir. fark önemlidir: bind kullanımda olmayan bir bağlantı noktası istiyor (böylece onu talep edip sunucu haline gelebiliyor) ve connect zaten kullanımda olan bir bağlantı noktası istiyor (böylece ona bağlanıp sunucuyla konuşabiliyor)


9

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

) (Bağlantı:

Connect () sistem çağrısı, dosya tanıtıcısı tarafından tanımlanan bir soketi, bağımsız değişken listesinde o ana bilgisayarın adresi ile belirtilen uzak bir ana bilgisayara bağlar.

Bazı soket türleri bağlantısızdır, en yaygın olarak kullanıcı datagram protokol soketleridir. Bu soketler için, connect özel bir anlam kazanır: veri göndermek ve almak için varsayılan hedef, bağlantısız soketlerde send () ve recv () gibi işlevlerin kullanımına izin vererek, verilen adrese ayarlanır.

connect (), hata kodunu temsil eden bir tamsayı döndürür: 0 başarıyı, -1 ise bir hatayı temsil eder.

bağlaması ():

bind (), bir adrese bir soket atar. Socket () kullanılarak bir soket oluşturulduğunda, ona yalnızca bir protokol ailesi verilir, ancak bir adres atanmaz. Bir adresle olan bu ilişki, soketin diğer ana bilgisayarlara bağlantıları kabul etmeden önce bind () sistem çağrısıyla gerçekleştirilmelidir. bind () üç argüman alır:

sockfd, bağlamayı gerçekleştirmek için soketi temsil eden bir tanımlayıcı. my_addr, bağlanılacak adresi temsil eden bir sockaddr yapısına işaretçi. addrlen, sockaddr yapısının boyutunu belirten bir socklen_t alanı. Bind () başarı durumunda 0 ve bir hata oluşursa -1 döndürür.

Örnekler: 1.) Connect'i Kullanma

#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.) Bağlama Örneği:

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

Umarım bu farkı açıklığa kavuşturur

Lütfen beyan edeceğiniz soket tipinin neye ihtiyacınız olduğuna bağlı olacağını unutmayın, bu son derece önemlidir


9

Ben aklınıza eğer sizin anlama yardımcı olacağını düşünüyorum connect()ve listen()karşıtları olarak yerine connect()ve bind(). Bunun nedeni arayabilir veya ihmal olmasıdır bind()daha önce aramak nadiren iyi bir fikir olsa, ya önce connect(), ya da daha önce aramak değil listen().

Sunucular ve istemciler açısından düşünmeye yardımcı oluyorsa, bu, listen()birincisinin ve connect()ikincisinin ayırt edici özelliğidir . bind()bulunabilir veya bulunmaz.

Sunucumuzun ve istemcimizin farklı makinelerde olduğunu varsayarsak, çeşitli işlevleri anlamak daha kolay hale gelir.

bind()yerel olarak hareket eder, yani çağrıldığı makinedeki bağlantının sonunu istenen adrese bağlar ve istenen bağlantı noktasını size atar. Bu, makinenin bir istemci veya sunucu olmasından bağımsız olarak yapar. connect()bir sunucuya, yani bir istemciden sunucudaki istenen adrese ve bağlantı noktasına bağlanan bir bağlantı başlatır. Kullanarak ona hangi adres ve bağlantı noktasından bağlanacağınızı bilmeniz için bu sunucu neredeyse kesinlikle daha bind()önce arayacaktır .listen()connect()

Eğer aramazsan bind(), bir liman ve adres örtük atanacak ve ya çağırdığınızda size yerel makinede bağlı connect()(istemci) ya da listen()(sunucu). Ancak bu, amaçlarının değil, ikisinin de bir yan etkisidir. Bu şekilde atanan bir bağlantı noktası geçicidir.

Burada önemli bir nokta, istemcinin bağlanmasına gerek olmamasıdır, çünkü istemciler sunuculara bağlanır ve bu nedenle sunucu, belirli bir şeye bağlanmak yerine, geçici bir bağlantı noktası kullanıyor olsanız bile istemcinin adresini ve bağlantı noktasını bilecektir. Öte yandan, sunucu listen()aramadan da arayabilse de bind(), bu senaryoda atanmış geçici bağlantı noktasını keşfetmeleri ve bunu ona bağlanmak istediği herhangi bir istemciye iletmeleri gerekir.

Bahsettiğiniz gibi connect()TCP ile ilgilendiğinizi varsayıyorum , ancak bu aynı zamanda UDP'ye de taşıyor, burada ilkinden bind()önce arama yapılmaması sendto()(UDP bağlantısızdır) ayrıca bir bağlantı noktası ve adresin dolaylı olarak atanmasına ve bağlanmasına neden olur. Bağlama olmadan çağıramayacağınız bir işlev recvfrom(), bir hata döndürecektir, çünkü atanmış bir bağlantı noktası ve bağlı adres olmadan, alınacak hiçbir şey yoktur (veya bir bağlamanın yokluğunu nasıl yorumladığınıza bağlı olarak çok fazla).


1

Çok uzun; Okuma: Fark, kaynağın (yerel) veya hedef adresin / bağlantı noktasının ayarlanmasıdır. Kısacası bind()kaynağı ve connect()hedefi belirleyin. TCP veya UDP'den bağımsız olarak.

bind()

bind()soketin yerel (kaynak) adresini ayarlayın. Bu, paketlerin alındığı adrestir. Soket tarafından gönderilen paketler bunu kaynak adresi olarak taşır, böylece diğer ana bilgisayar paketlerini nereye geri göndereceğini bilecektir.

Alma gerekli değilse soket kaynak adresi işe yaramaz. Hedef ana bilgisayar, bir veya daha fazla paket geldiğinde (yani alındı ​​bildirimi) bir onay gönderdiği için, TCP gibi protokollerin düzgün bir şekilde gönderilmesi için almanın etkinleştirilmiş olmasını gerektirir.

connect()

  • TCP'nin "bağlı" bir durumu vardır. connect()diğer tarafla bağlantı kurmaya çalışmak için TCP kodunu tetikler.
  • UDP'nin "bağlı" durumu yoktur. connect()yalnızca adres belirtilmediğinde paketlerin gönderileceği varsayılan bir adres ayarlayın. Ne zaman connect()kullanılmaz, sendto()ya sendmsg()hedef adresi içeren kullanılmalıdır.

Bir connect()gönderme işlevi çağrıldığında veya hiçbir adres bağlı olmadığında, Linux soketi otomatik olarak rastgele bir bağlantı noktasına bağlar. Teknik ayrıntılar için, inet_autobind()Linux çekirdeği kaynak koduna bakın.

Yan notlar

  • listen() yalnızca TCP'dir.
  • In AF_INET ailesi, soket kaynak veya hedef adresi ( struct sockaddr_in) bir IP adresine göre oluşur (bkz IP başlığı ) ve TCP veya UDP bağlantı noktası (bkz TCP ve UDP başlığını).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.