6-1. UDP에 대한 이해

 1) UDP 소켓의 특성
 UDP의 특성은 편지와 비슷하다.

 편지를 보내기 위해서는 일단 편지 봉투에다가 보내는 사람과 받는 사람의 주소 정보를 써야 한다. 그리고 우표를 붙이고, 우체통에 넣어주면 끝이다. 다만, 편지의 특성상 보내고 나서 상대방이 받았는지 아니면 못 받았는지 확인할 길은 없다. 또한 전송 도중에 편지가 분실되었다 하더라도, 역시 받는 사람이나 보내는 사람이나 이러한 상황을 알 길이 없다.

 따라서 UDP 소켓은 신뢰할 수 없는 데이터 전송 방법을 기본으로 하고 있다고 말할 수 있다. 하지만 이러한 특징이 오히려 장점으로 이용되기도 한다.

 TCP와 UDP의 기반이 되는 프로토콜은 IP이다. 그런데 IP 자체가 신뢰성 없는 전송 프로토콜을 의미한다.

 IP를 기반으로 프름 제어를 했던 TCP와는 달리, UDP는 데이터를 전송하는데 있어서 IP를 기반으로 흐름 제어를 해 주지 않는다. 따라서 프로토콜 자체가 상당히 간단하며, 이것이 바로 전송 속도에 있어서 TCP보다 빠른 이유가 된다.

 결론은 TCP가 주던 흐름 제어(flow control)를 UDP는 하지 않는다는 것이다. 따라서 UDP는 TCP에 비해 빠르다.

 2) UDP의 내부 동작
 UDP 소켓이 전송하는 데이터의 기본 단위를 Datagram이라고 한다.(일반적으로 UDP 패킷이라는 용어를 더 많이 쓰기도 한다). 이러한 데이터가 목적지 호스트로 길 찾아 가는데 까지 사용되는 프로토콜은 IP 이다.

 그 다음이 UDP의 역할이 두드러지는 부분이다. 바로 호스트 내에서 Port 정보를 통해 최종 목적지인 프로세스를 구분하는 일을 한다. 물론 TCP에서도 해 주는 작업이었다.

 몇몇 다른 일을 하기도 하지만, UDP의 가장 중요한 작업으로 Port 정보를 통해서 최종 목적지를 구분하여 주는 작업을 한다고 이해하면 충분하다.

 3) UDP의 효율적 사용
 네트워크 프로그래밍에서 거의 대부분이 TCP 소켓을 사용할 것 같지만, 인터넷을 기반으로 하는 경우 UDP가 사용되기도 한다. 여기서는 그 효율성을 설명한다.

 일단 생각보다는 UDP도 신뢰할 만하다는 것이다. 인터넷의 특성상 손실되는 정보들이 많이 있음에도 불구하고 생각보다는 신뢰할 만하다. 그래도 1000개의 패킷을 보냈는데 그 중 1개만 손실이 되어도 문제가 만큼 중요한 데이터들도 존재한다. 대표적인 예가 압축파일을 전송하는 경우이다. 압축파일을 특성상 파일의 일부만 손실되어도 복원하기가 어려워진다. 이러한 경우에는 TCP를 선택해야 것이다. 그러나 인터넷을 기반으로 실시간 영상 및 음성을 전송하는 경우에는 얘기가 조금 다른다. 멀티미디어 데이터는 그 측성상 일부가 손실이 되어도 크게 문제가 되지 않느다. 잠깐 동안의 화면 떨림 내지는 아주 작은 잡음 정도는 그냥 넘어가줄만하다. 하지만 실시간 서비스를 해야 하므로 속도는 상당히 중요한 요소가 된다. 이러한 경우가 UDP 소켓을 사용해야 하는 좋은 후보가 된다.

 그러나 언제나 UDP가 TCP에 비해서 빠른 속도를 내는 것은 아니다. TCP가 느린 이유가 가장 대표적인 것 두 가지를 들라고 하면, 하나는 데이터를 송,수신하기 전에 거치는 연결 설정 과정과 데이터를 송,수신한 후에 거치는 연결 종료 과정 대문이고, 또 하나는 흐름 제어(flow control)때문이다. 따라서 송,수신 하는 데이터의 양이 큰 경우(유지해야 하는 Session이 긴 경우)에는 UDP보다 여러 가지 측면에서 TCP가 표율적이 되고, 데이터의 양이 작은 경우(유지해야 하는 Session이 작고 잦은 연결이 발생하는 경우)에는 UDP가 TCP보다도 훨 씬 빠르게 동작 한다.

   
    6-2. UDP 기반 서버/클라이언트의 구현

 1) UDP 서버는 클라이언트와 연결되어 있지 않다.
 UDP 클라이언트와 서버는 연결(Connection) 상태가 존재하지 않는다. 즉 TCP 클라이언트와 서버처럼 데이터를 주고 받기 위해서 서로 연결을 설정하는 과정을 필요로 하지 않는다. 따라서 TCP 기반 서버 프로그램에서 호출하던 listen 함수와 accept 함수, 그리고 TCP 기반 클라이언트 프로그램에서 호출하던 connect  함수의 호출은 불필요하다. 오로지 소켓의 생성과 주소 할당만이 UDP 서버와 클라이언트가 구현해야 할 모든 것이다.

 2) UDP 서버의 소켓은 오로지 하나
 TCP에서는 소켓의 관계가 일 대 일이었다. 즉 서버에 여ㄹ명의 클라이언트가 연결되어 있는 상황이라면 총 열 개의 소켓을 생성했을 것이다. 그러나 UDP 서버는 오로지 하나의 소켓만 있으면 된다.

 따라서 일반적으로 UDP 기반으로 통신을 하는 호스트는 여러 개의 소켓을 생성하지 않느다.(그러나 경웨 따라서는 효율성을 근거로 여러 개의 소켓을 생성하기도 한다.)

 3) UDP 기반의 데이터 입,출력 함수
 TCP 소켓을 생성하고 나서 데이터를 전송하는 경우에는, 주소에 대한 정보를 따로 전달해 주지 않았다. 왜냐하면 TCP 소켓은 호스트와 연결된 상태에서 데이터를 주고 받기 때문이다. 즉 소켓은 데이터를 전송해야 하는 호스트의 주소 정보를 알고 있다.

 그러나 UDP 소켓은 연결 상태를 유지하지 않으므로(소켓은 단순히 우체통의 역할만 하므로), 데이터를 전송하는 함수 호출 반드시 보내고자 하는 곳의 주소 정보를 포함해야 한다.

 다음은 주소 정보를 포함해서 데이터를 전송하는 함수이다.

sendto (성공 시 전송된 바이트 수, 실패 시 -1 리턴) (Language : c)
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3.  
  4. int sendto(int sock, const void *msg, int len, unsigned flags, const struct sockaddr * addr, int addrlen)
 * sock : 데이터를 전송할 때 사용할 소켓의 파일 디스크립터를 인자로 넘겨 준다. 데이터를 네트워크로 전송하기 위해서는 기본적으로 소켓이 필요하다.
 * msg : 전송하고자 하는 데이터를 저장해 놓은 버퍼를 가리키는 포인터이다. 이 포인터가 가리키는 버퍼의 데이터가 전송된다.
 * len : msg 포인터가 가리키는 위치에서부터 몇 바이트를 전송할 것인지 그 크기를 인자로 넘겨준다.
 * flags : 옵션을 설정하는데 필요한 인자인데 일반적으로 0을 넣어주면 된다. 크게 사용되지 않는다.
 * addr : 전송하고자 하는 곳의 주소 정보로 초기화한 다음에 인자로 넘겨준다.
 * addrlen : addr 포인터가 가리키고 있는 구조체 변수의 크기를 인자로 넘겨준다.

 데이터를 수신하는 함수도 전송하는 함수인 sendto 함수와 마찬가지로 수신할 때에도 특정 클라이언트와 연결된 상태로 수신하는 것이 아니기 때문에 어디에서 데이터가 전송되었는지 알 없다. 따라서 함수 자체적으로 데이터가 전송된 위치 정보를 얻을 수 있는 기능을 제공한다.

 엄밀히 따지면 수신된 UDP 패킷이 자체적으로 주소 정보를 지니고 있고, 데이터 수신 함수는 이 주소 정보를 반환하는 것 뿐이다.

recvfrom (성공 시 수신한 바이트 수, 실패 시 -1 리턴) (Language : c)
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3.  
  4. int recvfrom(int sock, void *buf, int len, unsigned flags, struct sockaddr * addr, int * addrlen)
 * sock : 데이터를 수신할 때 사용할 소켓의 파일 디스크립터를 인자로 전달한다.
 * buf : 수신할 데이터를 저장할 버퍼를 가리키는 포인터이다.
 * len : 수신할 수 있는 최대 바이트 수이다. 일반적으로 buf가 가리키는 저장소의 크기를 넘지 않는다.
 * flags : 옵션을 설정하는데 필요한 인자
 * addr : 주소 정보 구조체 변수의 포인터를 인자로 넘긴다. 함수 호출이 끝나면, 데이터를 전송한 호스트의 주소 정보로 채워진다.
 * addrlen : addr 포인터가 가리키는 주소 정보 구조체 변수의 크기를 인자로 전달한다.

 4) UDP 기반의 에코 서버

uecho_server.c (Language : c)
  1. /***************************************************************************
  2. *            uecho_server.c
  3. *
  4. *  Fri Jan  4 19:07:45 2008
  5. *  Copyright  2008  pchero21
  6. *  pchero21@gmail.com
  7. ****************************************************************************/
  8.  
  9. /*
  10. *  This program is free software; you can redistribute it and/or modify
  11. *  it under the terms of the GNU General Public License as published by
  12. *  the Free Software Foundation; either version 2 of the License, or
  13. *  (at your option) any later version.
  14. *
  15. *  This program is distributed in the hope that it will be useful,
  16. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. *  GNU General Public License for more details.
  19. *
  20. *  You should have received a copy of the GNU General Public License
  21. *  along with this program; if not, write to the Free Software
  22. *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <arpa/inet.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32.  
  33. #define BUFSIZE 30
  34.  
  35. void error_handling(char *message);
  36.  
  37. int main(int argc, char **argv)
  38. {
  39.     int serv_sock;
  40.     char message[BUFSIZE];
  41.     int str_len;
  42.  
  43.     struct sockaddr_in serv_addr;
  44.     struct sockaddr_in clnt_addr;
  45.     int clnt_addr_size;
  46.    
  47.     if(argc != 2) {
  48.         printf("Usage : %s <port>\n", argv[0]);
  49.         exit(1);
  50.     }
  51.    
  52.     serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
  53.  
  54.     if(serv_sock == -1)
  55.         error_handling("UDP 소켓 생성 오류");
  56.    
  57.     memset(&serv_addr, 0, sizeof(serv_addr));
  58.     serv_addr.sin_family = AF_INET;
  59.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  60.     serv_addr.sin_port = htons(atoi(argv[1]));
  61.    
  62.     if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
  63.         error_handling("bind() error");
  64.    
  65.     while(1) {
  66.         clnt_addr_size = sizeof(clnt_addr);
  67.         str_len = recvfrom(serv_sock, message, BUFSIZE, 0, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
  68.         sendto(serv_sock, message, str_len, 0, (struct sockaddr*)&clnt_addr, sizeof(clnt_addr));
  69.     }
  70.     close(serv_sock);
  71.  
  72.     return 0;
  73. }
  74.  
  75. void error_handling(char *message)
  76. {
  77.     fputs(message, stderr);
  78.     fputc('\n', stderr);
  79.     exit(1);
  80. }
  81.  

 5) UDP 기반의 에코 클라이언트
 UDP 클라이언트 구현 시, TCP 클라이언트가 연결 요청을 할 때 사용했던 connect 함수의 호출은 존재하지 않는다. UDP 프로토콜은 연결 상태가 존재하지 않는다. 기억하자.

uecho_client.c (Language : c)
  1. /***************************************************************************
  2. *            uecho_client.c
  3. *
  4. *  Fri Jan  4 19:28:18 2008
  5. *  Copyright  2008  pchero21
  6. *  pchero21@gmail.com
  7. ****************************************************************************/
  8.  
  9. /*
  10. *  This program is free software; you can redistribute it and/or modify
  11. *  it under the terms of the GNU General Public License as published by
  12. *  the Free Software Foundation; either version 2 of the License, or
  13. *  (at your option) any later version.
  14. *
  15. *  This program is distributed in the hope that it will be useful,
  16. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. *  GNU General Public License for more details.
  19. *
  20. *  You should have received a copy of the GNU General Public License
  21. *  along with this program; if not, write to the Free Software
  22. *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <arpa/inet.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32.  
  33. #define BUFSIZE 30
  34.  
  35. void error_handling(char *message);
  36.  
  37. int main(int argc, char **argv)
  38. {
  39.     int sock;
  40.     char message[BUFSIZE];
  41.     int str_len, addr_size;
  42.  
  43.     struct sockaddr_in serv_addr;
  44.     struct sockaddr_in from_addr;
  45.        
  46.     if(argc != 3) {
  47.         printf("Usage : %s <IP> <port> \n", argv[0]);
  48.         exit(1);
  49.     }
  50.    
  51.     sock = socket(PF_INET, SOCK_DGRAM, 0);
  52.     if(sock == -1)
  53.         error_handling("socket() error!");
  54.    
  55.     memset(&serv_addr, 0, sizeof(serv_addr));
  56.     serv_addr.sin_family = AF_INET;
  57.     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
  58.     serv_addr.sin_port = htons(atoi(argv[2]));
  59.    
  60.     while(1) {
  61.         fputs("전송할 메시지를 입력하세요. (q to quit) : ", stdout);
  62.         fgets(message, sizeof(message), stdin);
  63.         if(!strcmp(message, "q\n"))
  64.             break;
  65.         sendto(sock, message, strlen(message), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  66.         addr_size = sizeof(from_addr);
  67.         str_len = recvfrom(sock, message, BUFSIZE, 0, (struct sockaddr*)&from_addr, &addr_size);
  68.         message[str_len] = 0;
  69.         printf("서버로부터 전송된 메시지 : %s", message);
  70.     }
  71.     close(sock);
  72.  
  73.     return 0;
  74. }
  75.  
  76. void error_handling(char *message)
  77. {
  78.     fputs(message, stderr);
  79.     fputc('\n', stderr);
  80.     exit(1);
  81. }
  82.  

 실행 화면

사용자 삽입 이미지

사용자 삽입 이미지


    6-3 데이터의 경계(Boundary)가 존재하는 UDP 소켓

 UDP는 데이터의 경계가 존재하는 프로토콜이다. 따라서 서버와 클라이언트가 데이터를 주고 받을 입,출력 함수 호출의 횟수는 조우요한 의미를 지닌다. 데이터 크기에 상관 없이 서버가 세 번의 출력 함수 호출을 통해서 데이터를 전송하면, 클라이언트는 반드시 세 번의 입력 함수 호출을 통해서 데이터를 수신해야 한다. 즉 입,출력 함수 호출 횟수를 반드시 일치시켜 줘야 한다는 것이다.

  1) 경계(Boundary) 에코 서버

becho_server.c (Language : c)
  1. /***************************************************************************
  2. *            becho_server.c
  3. *
  4. *  Sat Jan  5 00:12:43 2008
  5. *  Copyright  2008  pchero21
  6. *  pchero21@gmail.com
  7. ****************************************************************************/
  8.  
  9. /*
  10. *  This program is free software; you can redistribute it and/or modify
  11. *  it under the terms of the GNU General Public License as published by
  12. *  the Free Software Foundation; either version 2 of the License, or
  13. *  (at your option) any later version.
  14. *
  15. *  This program is distributed in the hope that it will be useful,
  16. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. *  GNU General Public License for more details.
  19. *
  20. *  You should have received a copy of the GNU General Public License
  21. *  along with this program; if not, write to the Free Software
  22. *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <arpa/inet.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32.  
  33. #define BUFSIZE 30
  34.  
  35. void error_handling(char *message);
  36.  
  37. int main(int argc, char **argv)
  38. {
  39.     int serv_sock;
  40.     char message[BUFSIZE];
  41.     int str_len, num = 0;
  42.  
  43.     struct sockaddr_in serv_addr;
  44.     struct sockaddr_in clnt_addr;
  45.     int clnt_addr_size;
  46.    
  47.     if(argc != 2) {
  48.         printf("Usage : %s <port> \n", argv[0]);
  49.         exit(1);
  50.     }
  51.  
  52.     serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
  53.     if(serv_sock == -1)
  54.         error_handling("create UDP socket error!");
  55.    
  56.     memset(&serv_addr, 0, sizeof(serv_addr));
  57.     serv_addr.sin_family = AF_INET;
  58.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  59.     serv_addr.sin_port = htons(atoi(argv[1]));
  60.    
  61.     if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
  62.         error_handling("bind() error!");
  63.    
  64.     sleep(5);
  65.    
  66.     while(1) {
  67.         clnt_addr_size = sizeof(clnt_addr);
  68.         sleep(1);
  69.         str_len = recvfrom(serv_sock, message, BUFSIZE, 0, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
  70.         printf("수신 번호 : %d\n", num++);
  71.         sendto(serv_sock, message, str_len, 0, (struct sockaddr*)&clnt_addr, sizeof(clnt_addr));
  72.     }
  73.  
  74.     return 0;
  75. }
  76.  
  77. void error_handling(char *message)
  78. {
  79.     fputs(message, stderr);
  80.     fputc('\n', stderr);
  81.     exit(1);
  82. }
  83.  

 2) 경계(Boundary) 에코 클라이언트

becho_client.c (Language : c)
  1. /***************************************************************************
  2. *            becho_client.c
  3. *
  4. *  Sat Jan  5 00:22:23 2008
  5. *  Copyright  2008  pchero21
  6. *  pchero21@gmail.com
  7. ****************************************************************************/
  8.  
  9. /*
  10. *  This program is free software; you can redistribute it and/or modify
  11. *  it under the terms of the GNU General Public License as published by
  12. *  the Free Software Foundation; either version 2 of the License, or
  13. *  (at your option) any later version.
  14. *
  15. *  This program is distributed in the hope that it will be useful,
  16. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. *  GNU General Public License for more details.
  19. *
  20. *  You should have received a copy of the GNU General Public License
  21. *  along with this program; if not, write to the Free Software
  22. *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <arpa/inet.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32.  
  33. #define BUFSIZE 30
  34.  
  35. void error_handling(char *message);
  36.  
  37. int main(int argc, char **argv)
  38. {
  39.     int sock;
  40.     char message[BUFSIZE];
  41.     int str_len, addr_size, i;
  42.  
  43.     char MSG1[] = "Good ";
  44.     char MSG2[] = "Evening ";
  45.     char MSG3[] = "Everybody!!";
  46.  
  47.     struct sockaddr_in serv_addr;
  48.     struct sockaddr_in from_addr;
  49.        
  50.     if(argc != 3) {
  51.         printf("Usage : %s <IP> <port> \n", argv[0]);
  52.         exit(1);
  53.     }
  54.    
  55.     sock = socket(PF_INET, SOCK_DGRAM, 0);
  56.     if(sock == -1)
  57.         error_handling("create UDP socket error!");
  58.    
  59.     memset(&serv_addr, 0, sizeof(serv_addr));
  60.     serv_addr.sin_family = AF_INET;
  61.     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
  62.     serv_addr.sin_port = htons(atoi(argv[2]));
  63.    
  64.     sendto(sock, MSG1, strlen(MSG1), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  65.     sendto(sock, MSG2, strlen(MSG2), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  66.     sendto(sock, MSG3, strlen(MSG3), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  67.        
  68.     for(i = 0; i < 3; i++) {
  69.         addr_size = sizeof(from_addr);
  70.         str_len = recvfrom(sock, message, BUFSIZE, 0, (struct sockaddr*)&from_addr, &addr_size);
  71.         message[str_len] = 0;
  72.         printf("서버로부터 수신된 %d 차 메시지 : %s \n", i, message);
  73.     }
  74.     close(sock);
  75.  
  76.     return 0;
  77. }
  78.  
  79. void error_handling(char *message)
  80. {
  81.     fputs(message, stderr);
  82.     fputc('\n', stderr);
  83.     exit(1);
  84. }
  85.  

 실행 화면

사용자 삽입 이미지

사용자 삽입 이미지


    6-4. connect 함수 호출을 통한 성능의 향상

 UDP 클라이언트를 구현할 때 connect 함수의 호출이 불필요하다고 하였다. 즉 연결 요청할 필요 없다는 의미이다. 그러나 connect 함수는 UDP 클라이언트에서 여전히 유용하다. 적절히 사용을 한다면 성능 향상이라는 큰 이점을 얻을 수 있다.

 1) UDP 소켓에서의 connect 함수의 의미
 TCP 소켓을 가지고 connect 함수를 호출하는 경우 ㄷ 가지 일이 진행되었다. 일단 소세에 호스트의 IP와 임의의 Port를 할당하게 되고, 그 다음에 서버로 연결 요청을 하게 된다.

 그러나 UDP 소켓을가지고 함수를 호출하는 경우는 그 의미가 달라진다. 연결 요청을 하는 과정은 생략되고, 오로지 소켓에 호스트의 IP와 임의의 Port를 할당하는 일만 하게 된다.

 2) connect 함수를 통해 얻어지는 이점
 네트워크를 통해 연결되어 있는 호스트와 데이터 송,수신을 하기 위해서는 소켓을 사용하게 된다. TCP 소켓으로 통신을 하는 호스트가 데이터를 보내기 위해서 write 함수를 호출하게 되면, 커널은 연결되어 있는 소켓을 통해서 데이터를 전송한다. read 함수를 호출했을 때도 마찬가지이다. 중요한 점은 커널은 소켓의 연결을 유지한다는 것이다. 이 연결 상태는 connect 함수 호출시 생성된다.(클라이언트와의 연결 상태를 의미하는 것이 아니다. 여기서 이야기하고자 하는 것은 데이터를 전송하기 위해서는 커널이 소켓과 연결되어 있어야 한다는 점을 말하는 것이다.)

 UDP 기반의 호스트의 경우 sendto, recvfrom 함수를 호출하기 전에는 커널이 소켓에 연결되어 있지 않다가, 함수 호출 시에 연결을 설정한다. 그리고 나서 함수 호출이 끝나는 경우에 연결을 종료한다.

 별 것 아닌 같지만 이 작업이 UDP 패킷을 송,수신 하는데 걸리는 정체 시간의 1/3을 차지한다. 따라서 이 시간만 줄여 주더라도 효율성을 높일 수 있다. 그렇다면 어떻게 커널과 소켓의 연결 상태를 유지시켜 놓을 수 있을까? UDP 소켓을 생성해서 사용할 경우에도 connect 함수를 호출해서 IP와 Port를 소켓에 할당해 놓으면 커널은 그 소켓과의 연결 상태를 계속 유지하게 된다. 뿐만 아니라, sendto, recvfrom 함수가 아닌 read, write와 같은 TCP 소켓이 통신하는데 사용하는 함수를 그대로 사용할 수 있게 된다. 이것 또한 하나의 장점이라고 수 있다.

 다음은 connect 함수 호출을 하는 UDP 기반의 에코 클라이언트 코드이다. 이전에 구현한 UDP 에코 서버와 함께 동작한다.

cecho_client.c (Language : c)
  1. /***************************************************************************
  2. *            cecho_client.c
  3. *
  4. *  Sat Jan  5 00:42:42 2008
  5. *  Copyright  2008  pchero21
  6. *  pchero21@gmail.com
  7. ****************************************************************************/
  8.  
  9. /*
  10. *  This program is free software; you can redistribute it and/or modify
  11. *  it under the terms of the GNU General Public License as published by
  12. *  the Free Software Foundation; either version 2 of the License, or
  13. *  (at your option) any later version.
  14. *
  15. *  This program is distributed in the hope that it will be useful,
  16. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. *  GNU General Public License for more details.
  19. *
  20. *  You should have received a copy of the GNU General Public License
  21. *  along with this program; if not, write to the Free Software
  22. *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <arpa/inet.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32.  
  33. int main(int argc, char **argv)
  34. {
  35.     int sock;
  36.     char message[30];
  37.     int str_len;
  38.  
  39.     struct sockaddr_in serv_addr;
  40.        
  41.     if(argc != 3) {
  42.         printf("Usage : %s <IP> <port> \n", argv[0]);
  43.         exit(1);
  44.     }
  45.    
  46.     sock = socket(PF_INET, SOCK_DGRAM, 0);
  47.  
  48.     memset(&serv_addr, 0, sizeof(serv_addr));
  49.     serv_addr.sin_family = AF_INET;
  50.     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
  51.     serv_addr.sin_port = htons(atoi(argv[2]));
  52.  
  53.     connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  54.        
  55.     while(1) {
  56.         fputs("전송할 메시지를 입력하세요. (q to quit) : ", stdout);
  57.         fgets(message, sizeof(message), stdin);
  58.    
  59.         if(!strcmp(message, "q\n"))
  60.             break;
  61.         write(sock, message, strlen(message));
  62.        
  63.         str_len = read(sock, message, sizeof(message) - 1);
  64.         message[str_len] = 0;
  65.         printf("서버로부터 전송된 메시지 : %s", message);
  66.     }
  67.     close(sock);
  68.  
  69.     return 0;
  70. }
  71.  

 실행 화면
사용자 삽입 이미지