9-1. 소켓의 옵션

 소켓에 설정할 수 있는 다양한 옵션들
===========================================
 Protocol Level      |      Option Name                        |   get     |   set
===========================================
SOL_SOCKET          |   SO_SNDBUF                             |      *      |    *
                             |   SO_RCVBUF                              |      *      |    *
                             |   SO_REUSEADDR                       |      *      |    *
                             |   SO_KEEPALIVE                          |      *      |    *
                             |   SO_BROADCAST                        |      *      |    *
                             |   SO_DONTROUTE                       |      *      |    *
                             |   SO_OOBINLINE                          |      *      |    *
                             |   SO_ERROR                                |      *      |    *
                             |   SO_TYPE                                   |      *      |    *
===========================================
IPPROTO_IP            |   IP_TOS                                      |      *      |     *
                             |   IP_TTL                                       |      *      |     *
                             |   IP_MULTICAST_TTL                      |      *     |      *
                             |   IP_MULTICAST_LOOP                   |      *      |     *
                             |   IP_MULTICAST_IF                        |      *      |      *
===========================================
IPPROTO_TCP         |   TCP_KEEPALIVE                         |      *      |     *
                             |   TCP_NODELAY                           |      *      |     *
                             |   TCP_MAXSEG                            |      *      |     *
===========================================

 소켓의 특성을 변경하는 옵션의 종류들은 계층별로 분류된다. IPPROT_IP 레벨의 옵션들은 IP 프로토콜에 관련된 사항들이며, IPPROTO_TCP는 TCP 프로토콜에 관련된 사항들이다. 또한 SOL_SOCKET 레벨의 옵션들은 소켓에 대한 가장 일반적인 옵션들이라고 생각하면 된다

 거의 모든 옵션은 설정 상태를 참조해 볼 수도, 변경할 수도 있다.(단 일부 옵션은 참조만 가능하거나, 설정 상태를 변경하는 것만 가능한 것도 있다.)

 우선 현재 설정 상태 정보를 가져오는 함수이다.

getsockopt (성공 시 0, 실패 시 -1 리턴) (Language : c)
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3.  
  4. int getsockopt(int sock, int level, int optname, void *potval, socklen_t *optlen);
 * sock : 설정 상태를 확인해 보고 싶은 소켓의 파일 디스크립터를 인자로 전달한다.
 * level : 확인할 옵션의 프로토콜 레벨(Protocol Level)을 인자로 전달한다.
 * optname : 확인할 옵션의 이름을 전달한다.
 * optal : 확인 결과를 저장할 버퍼를 가리키는 포인터를 전달한다.
 * optlen : optval 포인터가 가리키는 버퍼의 크기를 전달한다. 함수 호출이 완료되면, 전달된 포인터가 가리키는 변수에는 버퍼에 저장된 확인 결과의 길이가 바이트 단위로 저장된다.

 다음은 옵션을 변경하는 함수이다.

setsockopt (성공 시 0, 실패 시 -1 리턴) (Language : c)
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3.  
  4. int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
 * sock : 설정 상태를 변경하고자 하는 소켓의 파일 디스크립터를 인자로 전달한다.
 * level : 변경할 옵션의 프로토콜 레벨을 인자로 전달한다.
 * optname : 변경할 옵션의 이름을 전달한다.
 * optval : 변경할 옵션의 값을 저장한 버퍼의 포인터를 전달한다.
 * optlen : 전달하는 옵션의 바이트 단위 길이를 전달한다.

 다음은 이를 사용한 코드이다.

sock_type.c (Language : c)
  1. /***************************************************************************
  2. *            sock_type.c
  3. *
  4. *  Tue Jan  8 18:24:27 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 <unistd.h>
  28. #include <arpa/inet.h>
  29. #include <sys/types.h>
  30. #include <sys/socket.h>
  31.  
  32. void error_handling(char *message);
  33.  
  34. int main(int argc, char **argv) {
  35.  
  36.     int tcp_sock, udp_sock;
  37.     int sock_type = -1;
  38.     socklen_t optlen;
  39.     int state;
  40.  
  41.     optlen = sizeof(sock_type);
  42.     tcp_sock = socket(PF_INET, SOCK_STREAM, 0);
  43.     udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
  44.  
  45.     printf("SOCK_STREAM : %d \n", SOCK_STREAM);
  46.     printf("SOCK_DGRAM : %d \n", SOCK_DGRAM);
  47.  
  48.     state = getsockopt(tcp_sock, SOL_SOCKET, SO_TYPE, &sock_type, &optlen);
  49.     if(state)
  50.         error_handling("getsockopt() error!");
  51.     printf("첫 번째 소켓 타입은 %d \n", sock_type);
  52.    
  53.     state = getsockopt(udp_sock, SOL_SOCKET, SO_TYPE, &sock_type, &optlen);
  54.     if(state)
  55.         error_handling("getsockopt() error!");
  56.     printf("두 번째 소켓 타입은 %d \n", sock_type);
  57.    
  58.     return 0;
  59. }
  60.  
  61. void error_handling(char *message)
  62. {
  63.     fputs(message, stderr);
  64.     fputc('\n', stderr);
  65.     exit(1);
  66. }
  67.  

 실행 결과
사용자 삽입 이미지

 소켓의 옵션 대부분이 설정 상태의 확인과 변경이 가능하다. 그러나 일부 옵션은 상태 확인만 가능하거나, 변경만 가능한 옵션도 있는데, SO_TYPE이 대표적인 예이다. 이 옵션은 상태 확인만 가능하고 변경은 불가능하다. 즉 소켓의 타입은 소켓 생성 시에 결정되면 변경할 수 없다는 뜻이 된다.


    9-2. SO_SNDBUF & SO_RCVBUF

 소켓 생성 시 기본적으로 커널에 의해서 입력과 출력을 위한 버퍼가 생성된다.

 SO_SNDBUF는 소켓 생성 시 제공되는 출력 버퍼의 크기와 관련된 옵션이고, SO_RCVBUF는 소켓 생성 시 제공되는 입력 버퍼의 크기와 관련된 옵션이다.

 다음은 이를 사용한 코드이다.

get_buf.c (Language : c)
  1. /***************************************************************************
  2. *            sock_buf.c
  3. *
  4. *  Tue Jan  8 18:37:10 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 <unistd.h>
  28. #include <sys/types.h>
  29. #include <sys/socket.h>
  30.  
  31. void error_handling(char *message);
  32.  
  33. int main(int argc, char **argv)
  34. {
  35.  
  36.     int sock;
  37.     int snd_buf;
  38.     int rcv_buf;
  39.     int state;
  40.     socklen_t len;
  41.  
  42.     sock = socket(PF_INET, SOCK_STREAM, 0);
  43.  
  44.     len = sizeof(snd_buf);
  45.     state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_buf, &len);
  46.     if(state)
  47.         error_handling("getsockopt() error!");
  48.    
  49.     len = sizeof(rcv_buf);
  50.     state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, &len);
  51.     if(state)
  52.         error_handling("getsockopt() error!");
  53.    
  54.     printf("데이터 입력을 위한 소켓의 버퍼 크기 : %d \n", rcv_buf);
  55.     printf("데이터 출력을 위한 소켓의 버퍼 크기 : %d \n", snd_buf);
  56.    
  57.     return 0;
  58. }
  59.  
  60. void error_handling(char *message)
  61. {
  62.     fputs(message, stderr);
  63.     fputc('\n', stderr);
  64.     exit(1);
  65. }
  66.  

 실행 결과
사용자 삽입 이미지

 출력 결과를 보면 예상과는 전혀 다른 결과를 보여주고 있다는 것을 알 수 있다. 왜냐하면 입,출력 버퍼의 문제는 상당히 주의 깊게 다뤄져야 하기 때문에 프로그래머가 요구하는 크기로 정확히 맞춰주지 않는다. 다만 setsockopt 함수 호출응ㄹ 통해서 버퍼 크기를 인자로 전달되는 값을 참조하여 버퍼의 크기를 설정할 뿐이다.

 코드에도 디폴트 크기보다 작은 크기의 버퍼를 요구한 결과 작은 크기의버퍼가 생성되었음을 볼 수 있다.


    9-3. SO_REUSEADDR

 1) 주소 할당 시 에러(Binding Error)의 발생
 일단 다음 코드를 보자.

reuseaddr.c (Language : c)
  1. /***************************************************************************
  2. *            reuseaddr.c
  3. *
  4. *  Tue Jan  8 22:02:15 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 TRUE 1
  34. #define FALSE 0
  35.  
  36. void error_handling(char *message);
  37.  
  38. int main(int argc, char **argv)
  39. {
  40.     int serv_sock;
  41.     int clnt_sock;
  42.     char message[30];
  43.     int str_len;
  44.  
  45.     int option;
  46.     socklen_t optlen;
  47.  
  48.     struct sockaddr_in serv_addr;
  49.     struct sockaddr_in clnt_addr;
  50.     int clnt_addr_size;
  51.    
  52.     if(argc != 2) {
  53.         printf("Usage : %s <port>\n", argv[0]);
  54.         exit(1);
  55.     }
  56.    
  57.     serv_sock = socket(PF_INET, SOCK_STREAM, 0);
  58.     if(serv_sock == -1)
  59.         error_handling("socket() error!");
  60.    
  61.     optlen = sizeof(option);
  62.     option = TRUE;
  63.    
  64. /*    setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); */
  65.     memset(&serv_addr, 0, sizeof(serv_addr));
  66.     serv_addr.sin_family = AF_INET;
  67.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  68.     serv_addr.sin_port = htons(atoi(argv[1]));
  69.    
  70.     if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))
  71.         error_handling("bind() error!");
  72.    
  73.     if(listen(serv_sock, 5) == -1)
  74.         error_handling("listen error!");
  75.     clnt_addr_size = sizeof(clnt_addr);
  76.     clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
  77.        
  78.     /* 데이터 수신 및 전송 */
  79.     while((str_len = read(clnt_sock, message, sizeof(message))) != 0) {
  80.         write(clnt_sock, message, str_len);
  81.         write(1, message, str_len);
  82.     }
  83.     close(clnt_sock);
  84.     return 0;
  85. }
  86.  
  87. void error_handling(char *message)
  88. {
  89.     fputs(message, stderr);
  90.     fputc('\n', stderr);
  91.     exit(1);
  92. }
  93.  

 이 코드는 일반적인 에코 서버이다. 여지껏 작성했던 에코 클라이언트와 작동하니 함께 실행해 보자. (주석 처리 되어 있는 코드는 그대로 두고 실행 해야 한다.)

 잘 작동한다면 실행하는 과정의 순서를 다음과 같이 진행해 보자.

 * 클라이언트에서 연결 종료 요청하기
 클라이언트와 서버가 연결된 상태에서, 클라이언트가 먼저 서버로 종료 요청을 하도록 하자. 이는 클라이언트가 close 함수 호출을 통해서 소켓을 종료한다는 뜻이다. 'q'를 누르고 엔터키를 누르거나, 'Ctrl-C'키를 누르게 되면 소켓이 종료가 되면서 프로그램도 종료하게 된다. 그러나 이렇게 해서 소켓을 종료 해도 클라이언트 소켓은 바로 소멸되는 것이 아니라, 서버로 FIN 메시지 전송을 시작으로 해서 제대로 된 종료, 즉 four-way handshaking 과정을 거치게 된다. 이제 서버도 Ctrl-C 키를 눌러서 종료한 다음, 서버를 다시 실행해 보자. 서버가 바로 실행되는 것을 확인 할 있다. 전혀 문제가 없다.

 실행 결과
사용자 삽입 이미지

사용자 삽입 이미지

 * 서버에서 연결 종료 요청하기
 이번에는 순서를 바꿔서 종료를 해 보자. 일단 서버를 먼저 동작시키고 클라이언트도 연결 상태에 놓이게 한다. 그 다음에 클라이언트를 종료시키는 것이 아니라, 먼저 서버를 종료시킨다. 이렇게 되면 이번에도 역시 서버 영역에서 클라이언트와 연결 상태에 있던 소켓이 바로 소멸되지 않고, 클라이언트 영역으로 FIN 메시지를 전송하게 도니다. 이를 시작으로 four-way handshaking 과정을 거치게 된다. 그 다음에 다시 한번 서버를 실행 시켜 보자.

 
사용자 삽입 이미지

 bind 함수 호출에서 문제가 발생하고 있음을 보여 준다. 이 상태로 대략 여유 있게 3분 정도 지나고나서 다시 실행 보자. 이번에는 bind 함수 호출에서 오류가 발생하지 않고 제대로 동작할 것이다.

 2) TIME-WAIT 상태
 이는 four-way handshaking에서 일어나는 문제이다. 먼저 종료를 요청한 쪽에서 four-way handshaking 과정이 끝난 상태에서 소켓이 바로 소멸되는 것이 아니라, TIME-WAIT 상태로 들어간다는 것이다.

 즉 TIME-WAIT 상태가 진행될 동안에 서버는 여전히 존재하고 있다는 뜻이 된다. 따라서 이러한 상태에서 bind 함수를 호출할 때 오류가 발생하는 것은 당연하다. 이미 IP와 Port가 사용되고 있기 때문이다.

 그렇다면 TIME-WAIT 상태는 무엇 때문에 존재하는 것일까? A가 먼저 종료 요청을 보냈다고 가정하자. 만약 마지막 종료 메시지를 전송하고 나서, 바로 종료되었다고 했을 때, A가 B에게 마지막으로 전달한 이 ACK가 중간에 소멸되어 버렸다. 만약 그렇게 된다면 B클라이언트는 좀 전에 자신이 보낸 FIN 메시지를 A가 받지 못했다고 생각하고, 다시 한번 FIN을 전송하게 될 것이다. 그러나 이미 A는 종료된 상태에 있기 때문에 B는 영원에 FIN에 대한 마지막 ACK 메시지를 받지 못하게 될 것이다.

 그러나 A가 TIME-WAIT 상태로 대기 중에 있었다면, 마지막 ACK의 재전송이 진행되었을 것이고 B는 무사히 종료하게 된다. 따라서 먼저 종료를 요청하는 호스트는 TIME-WAIT 과정을 필요로 하게 되는 것이다.

 3) 주소의 재활용
 즉 내용을 정리하면 다음과 같다. 클라이언트가 연결되어 있는 서버가 먼저 종료 요청을 할 경우 four-way handshaking 과정을 거친 다음 TIME-WAIT 상태로 들어가게 된다. 이 TIME-WAIT 상태가 필요한 이유는 four-way handshaking 과정의 마지막으로 전송되는 ACK가 소멸되었을 때 재 전송을 하기 위한 것이며, 따라서 TIME-WAIT 상태가 끝날 때까지 IP와 Port는 할당 될 수 없다. 결국 TIME-WAIT 상태가 완전히 끝나서야 서버를 가동 시킬 수 있다는 뜻이 된다. 하지만 이런 TIME-WAIT도 문제가 있다.

 만약 아주 중요한 서버가 있다고 가정했을때...(예를 들면 은행이나 금융권) 서버쪽에서 먼저 시스템을 재 기동해야하는 상황이 벌어졌다고 하면 재기동 후, TIME-WAIT 상태가 종료될때까지 시스템을 다시 재기동할 수 없는 사태가 발생하게 된다. 이는 손실이 아닐 수 없다.

 이럴 경우 소켓의 옵션 중 SO_REUSEADDR의 상태를 변경해 주면 된다. 옵션 값이 1(TRUE)인 경우에는, TIME-WAIT 상태에 있는 소켓에 할당되어 있는 IP 주소와 Port를 새로 시작하는 소켓에 할당해 주게 된다.

 디폴트 값은 0(FALSE)이다. 따라서 반드시 변경을 해 주어야 한다. reuseaddr.c 예제에서 주석 처리되어 있는 코드가 이에 해당한다. 주석을 해제하고 실행하면 문제없이 서버가 잘 동작할 것이다.


    9-4. TCP_NODELAY

 1) Nagle 알고리즘
 Nagle 알고리즘은 네트워크 상에서 돌아다니는 패킷들이 흘러 넘치는 일이 없도록 하기 위해서 1984년에 제안된 알고리즘이다. TCP 프로토콜상에서 구현되며 단순하다는 특징을 지니고 있다.

 Nagle 알고르짐은 아주 간단하다. 한마디로 정의하면 "기존에 전송한 패킷을 있을 경우 그 패킷에 대한 ACK를 받아야만 다음 전송을 진행하는 알고리즘"이다.
사용자 삽입 이미지


 Nagle 알고리즘이 작동 중인 서버에서 'Good' 이란 문자열을 전송해보자. G부터 d까지 차례로 출력 버퍼로 전송이 것이다. G이 들어 온 경우에는 이전에 전송했던 패킷이 없으므로 바로 전송을 진행한다. 그리고 나서 버퍼에 o, o, d가 계속해서 들어와도 ACK를 받지 못했으므로, 전송하지 않고 대기한다.(물론 Good이라는 문자열을 전송할 때 늘 이렇게 된다는 것은 아니다. 한 가지 경우의 수를 제시한 것 뿐이다.)

 그리고 잠시 후에 G에 대한 ACK를 수신한다. 그리고 나서, 버퍼에 존재하는 o, o, d를 하나의 패킷으로 구성하여 전송해 준다. 그리고 이에 대한 마지막 ACK도 수신한다. 전체 데이터를 전송하는데 총 네 번의 패킷 송.수신이 있었다.(ACK까지 포함해서)

 이번에는 Nagle 알고리즘을 적용하지 않은 상태에서 "Good"이라는 문자 데이터를 전송하는경우의 데이터 송,수신 횟수를 계산해 보자. 총 8개의 패킷을 만들어 냈음을 알 수 있다. Nagle 알고리즘이 적용되지 않으면 전송할 데이터가 있는 경우 ACK를 기다리지 않고, 바로 전송해 버리기 때문이다.

 이것은 네트워크의 트래픽(Traffic : 네트워크에 걸리는 부하난 혼잡의 정도를 의미함)에는 좋지 않은 영향을 미친다. 1바이트를 전송하더라도 기본적으로 포함되어야 하는 헤더의 크기가 수십 바이트에 이르기 때문이다. 따라서 네트워크의 효율적 사용을 위해서는 Nagle 알고리즘은 반드시 적용되어야 한다.

 즉, 결론은 다음과 같다. Nagle 알고리즘을 적용하지 않으면 속도의 향상을 가져올 수는 있으나, 무조건 Nagle 알고리즘을 적용하지 않을 경우에는 네트워크에 상당한 부하ㄴ를 주게 되어 더 좋지 않은 결과를 얻게 될 수도 있다. 따라서 TCP 소켓은 디폴트(Default)로 Nagle 알고리즘을 적용하고 있으며, 반드시 분명한 이유가 있을 때에만 Nagle 알고리즘을 중지시켜야 기대하는 효과를 얻을 수 있게 된다.

 2) Nagle 알고리즘의 중단 요청
 TCP_NODELAY 옵션이 1(TRUE)로 설정되는 경우, Nagle 알고리즘을 적용하지 않겠다는 의미이고, 0(FALSE)인 경우 Nagle 알고리즘을 적용한다는 의미가 된다.

 다음은 이를 이용한 코드이다.

nagle.c (Language : c)
  1. /***************************************************************************
  2. *            nagle.c
  3. *
  4. *  Tue Jan  8 22:34:47 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 <unistd.h>
  28. #include <sys/types.h>
  29. #include <sys/socket.h>
  30. #include <netinet/tcp.h>
  31. #include <netinet/ip.h>
  32.  
  33. #define TRUE 1
  34. #define FALSE 0
  35.  
  36. int main(int argc, char **argv)
  37. {
  38.     int sock;
  39.     int state, opt_val, opt_len;
  40.  
  41.     sock = socket(PF_INET, SOCK_STREAM, 0);
  42.  
  43.     /* 디폴트 nagle 알고리즘 설정 상태 확인 */
  44.     state = getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, &opt_len);
  45.     if(state) {
  46.         puts("getsockopt() error!");
  47.         exit(1);
  48.     }
  49.     printf("디폴트 nagle 알고리즘 : %s \n", opt_val ? "비설정" : "설정");
  50.  
  51.     /* nagle 알고리즘을 DISALBE 시킨다 */
  52.     opt_val = TRUE;
  53.     state = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, sizeof(opt_val));
  54.     if(state) {
  55.         puts("setsockopt() error!");
  56.         exit(1);
  57.     }
  58.    
  59.     /* 변경된 nagle 알고리즘 확인 */
  60.     getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, &opt_len);
  61.     printf("변경된 nagle 알고리즘 : %s \n", opt_val ? "비설정" : "설정");
  62.  
  63.     close(sock);
  64.     return 0;
  65. }
  66.  

 실행 결과
사용자 삽입 이미지