소켓 connect () 대 bind ()


121

connect()bind()시스템 호출 모두 소켓 파일 설명자를 주소 (일반적으로 ip / 포트 조합)에 '연결'합니다. 그들의 프로토 타입은 다음과 같습니다.

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

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

두 통화의 정확한 차이점은 무엇입니까? 때 하나를 사용해야 connect()언제 bind()?

특히 일부 샘플 서버 클라이언트 코드에서 클라이언트가 사용 connect()중이고 서버가 bind()호출을 사용 하고 있음을 발견했습니다 . 이유는 나에게 완전히 명확하지 않았습니다.


19
한 문장으로 : bind는 로컬 주소, connect는 원격 주소입니다.
SHR

답변:


230

이해를 높이기 위해 정확히 바인딩하고 연결하는 위치를 찾아 보겠습니다.

Sourav가 명확히 한 것처럼 두 호출의 위치 지정 외에도

bind ()는 소켓을 로컬 주소와 연결합니다. [이것이 바로 서버 측이 바인드하는 이유이므로 클라이언트가 해당 주소를 사용하여 서버에 연결할 수 있습니다.] connect ()는 원격 [서버] 주소에 연결하는 데 사용됩니다. 이것이 클라이언트 측인 이유입니다. , connect [읽기 : 서버에 연결]이 사용됩니다.

특정 역할과 해당 구현으로 인해 (동일한 컴퓨터에 클라이언트 / 서버가있는 경우에도) 서로 바꿔서 사용할 수 없습니다.

이러한 호출을 TCP / IP 핸드 셰이크 상호 연관시키는 것이 좋습니다.

여기에 이미지 설명 입력

따라서 여기에 SYN을 보낼 사람은 connect ()입니다. bind ()는 통신 끝점을 정의하는 데 사용됩니다.

도움이 되었기를 바랍니다!!


1
감사합니다 형제. 다이어그램을 사용하면 모든 것을 빠르게 이해할 수 있습니다. udp를 사용하는 경우 차이점이 무엇인지 알 수 있습니까?
apm

8
accept () <br>은 클라이언트에서 연결될 때까지 <br> 블록 아래로 이동해야합니다
tschodt

p2p 네트워크의 네트워크에있는 모든 노드가 bind를 사용해야한다고 생각합니다. 맞습니까?
kapil

46

하나의 라이너 : bind() 자신의 주소로, connect()원격 주소로.

의 man 페이지에서 인용 bind()

bind ()는 addr에 의해 지정된 주소를 파일 기술자 sockfd가 참조하는 소켓에 할당합니다. addrlen은 addr가 가리키는 주소 구조의 크기 (바이트)를 지정합니다. 전통적으로이 작업을 "소켓에 이름 할당"이라고합니다.

그리고, 동일에서 connect()

connect () 시스템 호출은 파일 설명자 sockfd가 참조하는 소켓을 addr로 지정된 주소에 연결합니다.

명확히하기 위해

  • bind()소켓을 로컬 주소와 연결합니다. [ bind그래서 클라이언트가 해당 주소를 사용하여 서버에 연결할 수 있도록 서버 측 s.]
  • connect() 원격 [서버] 주소에 연결하는 데 사용되므로 클라이언트 측에서 연결 [읽기 : 서버에 연결]이 사용됩니다.

예를 들어 서버와 클라이언트 프로세스가 모두 동일한 시스템에서 실행되는 경우 서로 바꿔서 사용할 수 있습니까?
Siddhartha Ghosh

1
@SiddharthaGhosh 아니요. 클라이언트와 서버가 동일한 시스템에 있지만 여전히 프로세스 다릅니다. 두 API 모두 자체 용도로 사용됩니다. 그들은 결코interchangeable
Sourav Ghosh

이 맥락에서 로컬 및 원격이란 정확히 무엇을 의미합니까?
Siddhartha Ghosh

@SiddharthaGhosh- local> 프로세스 자체, remote-> 다른 프로세스.
Sourav Ghosh

@SouravGhosh 그래서 이것은 클라이언트 측에서 바인딩 할 포트를 지정할 수 없음을 의미합니까?
Hengqi Chen

12

bind는 실행중인 프로세스에 포트를 요청하도록 지시합니다. 즉, 자신을 포트 80에 바인딩하고 들어오는 요청을 수신해야합니다. bind를 사용하면 프로세스가 서버가됩니다. connect를 사용할 때 이미 사용중인 포트에 연결하도록 프로세스에 지시합니다. 프로세스가 클라이언트가됩니다. 차이점은 중요합니다. bind는 사용 중이 아닌 포트를 원하고 (권장하고 서버가 될 수 있도록) connect는 이미 사용중인 포트를 원합니다 (따라서 연결하고 서버와 통신 할 수 있음).


9

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

잇다():

connect () 시스템 호출은 파일 설명 자로 식별되는 소켓을 인수 목록에서 해당 호스트의 주소로 지정된 원격 호스트에 연결합니다.

특정 유형의 소켓은 비 연결형이며 가장 일반적으로 사용자 데이터 그램 프로토콜 소켓입니다. 이러한 소켓의 경우 connect는 특별한 의미를 갖습니다. 데이터를 보내고 받기위한 기본 대상이 주어진 주소로 설정되어 연결없는 소켓에서 send () 및 recv ()와 같은 함수를 사용할 수 있습니다.

connect ()는 오류 코드를 나타내는 정수를 반환합니다. 0은 성공을 나타내고 -1은 오류를 나타냅니다.

묶다():

bind ()는 소켓을 주소에 할당합니다. socket ()을 사용하여 소켓을 만들면 프로토콜 패밀리 만 제공되고 주소는 할당되지 않습니다. 주소와의이 연관은 소켓이 다른 호스트에 대한 연결을 허용하기 전에 bind () 시스템 호출로 수행되어야합니다. bind ()는 세 가지 인수를 사용합니다.

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는 연결이 없음) 전에 호출하지 않으면 포트와 주소가 암시 적으로 할당되고 바인딩됩니다. 바인딩없이 호출 할 수없는 함수는이며 recvfrom(), 할당 된 포트와 바인딩 된 주소가 없으면 수신 할 항목이 없기 때문에 오류를 반환합니다 (또는 바인딩 부재를 해석하는 방법에 따라 너무 많음).


1

너무 오래; 읽지 않음 : 차이점은 소스 (로컬) 또는 대상 주소 / 포트가 설정되었는지 여부입니다. 요컨대, bind()소스를 connect()설정하고 목적지를 설정하십시오. TCP 또는 UDP에 관계없이.

bind()

bind()소켓의 로컬 (소스) 주소를 설정합니다. 이것은 패킷이 수신되는 주소입니다. 소켓에서 보낸 패킷은 이것을 소스 주소로 전달하므로 다른 호스트는 패킷을 다시 보낼 위치를 알 수 있습니다.

수신이 필요하지 않으면 소켓 소스 주소는 쓸모가 없습니다. TCP와 같은 프로토콜은 하나 이상의 패킷이 도착했을 때 대상 호스트가 확인 (예 : 확인)을 다시 보내므로 제대로 전송하려면 수신을 활성화해야합니다.

connect()

  • TCP는 "연결된"상태입니다. connect()TCP 코드를 트리거하여 다른쪽에 연결을 시도합니다.
  • UDP에는 "연결된"상태가 없습니다. connect()주소가 지정되지 않은 경우에만 기본 주소를 패킷이 전송되는 위치로 설정하십시오. 때 connect()사용되지 않는, sendto()또는 sendmsg()대상 주소를 포함 사용해야합니다.

경우 connect()에는 주소가 바인딩되지 않거나 송신 함수가 호출되고, 리눅스는 자동으로 임의의 포트에 소켓을 바인딩합니다. 기술적 세부 사항 inet_autobind()은 Linux 커널 소스 코드를 참조하십시오.

사이드 노트

  • listen() TCP 전용입니다.
  • 에서 AF_INET의 가족, 소켓의 소스 또는 대상 주소 ( struct sockaddr_in) IP 주소로 구성된다 ( IP 헤더 ) 및 TCP 또는 UDP 포트 (참조 TCPUDP 헤더를).
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.