TCP socket library 만들기 [다섯번째] : 최종테스트 및 소스첨부

자, 이번 시간에는 지금까지 만든 tcp library 를 이용하여 사용자 메시지까지 주고받아보겠습니다.
정말 설레지 않나요 ?  나만 설렌가…;;;
자신이 만든 코드를 시험하기전 기대하는 마음이 드는건 참 즐거운 일입니다. ^^

다음은 지금까지 만든 파일 List 입니다. 파일은 아직 몇개 안되니 주석을 보시면 어떤 파일인지 아실겁니다.

sh> ls -al
total 32
drwxrwxr-x   3 bitmyer bitmyer 4096 Nov 30 03:57 ./
drwxrwxr-x. 14 bitmyer bitmyer 4096 Nov 25 10:25 ../
-rw-rw-r--   1 bitmyer bitmyer 2014 Nov 30 03:57 Makefile              // library makefile
-rw-rw-r--   1 bitmyer bitmyer 3460 Nov 30 03:40 socket_base.cpp  // socket_base 함수구현
-rw-rw-r--   1 bitmyer bitmyer  947 Nov 30 03:29 socket_base.h      // socket_base class 정의
-rw-rw-r--   1 bitmyer bitmyer 2418 Nov 30 03:03 tcp_socket.cpp     // tcpsvr, tcpcli 함수구현
-rw-rw-r--   1 bitmyer bitmyer  564 Nov 30 02:33 tcp_socket.h         // tcpsvr, tcpcli class 정의
drwxrwxr-x   2 bitmyer bitmyer 4096 Nov 30 05:10 test/

sh> ls -al test/*
-rw-rw-r-- 1 bitmyer bitmyer  726 Nov 30 03:57 test/Makefile           // test binary makefile
-rw-rw-r-- 1 bitmyer bitmyer  589 Nov 30 03:41 test/tcpcli.cpp         // tcp client program
-rw-rw-r-- 1 bitmyer bitmyer 1595 Nov 30 03:28 test/tcpsvr.cpp       // tcp server program

아래가 tcpcli.cpp 코드입니다.
buffer 에 메시지 넣고 cli->send() 함수를 호출하는 부분이 추가되었습니다.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <tcp_socket.h>

int main()
{
    int      i;
    int      ret;
    int      sock;
    char     buf[64];
    tcpcli * cli = new tcpcli(1,0,0);

    sock = cli->connect( (char *)"127.0.0.1", 11111 );
    if( sock < 0 ) exit(1);
    printf("open okay...[%d]n", sock);

    memset(buf, 0x00, sizeof(buf));

    for(i=0; i<10; i++)
    {
        sprintf(buf, "this is [%d]th test message !!!!", i);

        ret = cli->send(buf, strlen(buf));
        printf("send... ret (%d)n", ret);
    }

    // sleep here

    return 0;
}

다음은 tcpsvr.cpp 코드입니다.
마찬가지로 buf 선언 후 accept socket 에 대해 event 가 발생하면 svr->recv() 함수를 호출하여 데이터를 읽어들이는 부분이 추가되었습니다.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <tcp_socket.h>

int main()
{
    int             ret;
    int             sock = -1;
    int             accept_sock = -1;
    struct timeval  timeout;
    fd_set          fd;
    char            buf[64];
    tcpsvr *        svr = new tcpsvr(1,1,0);  // tcpsvr 객체 생성 (socket option 값 지정)

    // server socket 준비 및 listen
    sock = svr->open( 11111 );
    if( sock < 0 ) exit(1);

    printf("open okay...[%d]n", sock);

    memset(buf, 0x00, sizeof(buf));

    while(1)
    {
        // event 가 없을 경우 select 에서 기다려줄 시간 (timeout)
        timeout.tv_sec  = 1;
        timeout.tv_usec = 0;

        FD_ZERO(&fd);  
        if( sock > 0 ) FD_SET( sock, &fd );  // listen socket 을 fdset 에 셋팅
        if( accept_sock > 0 ) FD_SET( accept_sock, &fd );  // 데이터 수신 socket 셋팅

        // select 를 통해 fdset 에 설정된 FD 에 대해 Event 감시
        if( (ret = select( FD_SETSIZE, &fd, NULL, NULL, &timeout)) <= 0 )
        {
            // timeout 이나 error 이면 잠깐 쉬었다가 다시 시도
            // sleep here
            continue;
        }

        // sock (listen socket) 에 Event 가 감지되었을 경우
        if( FD_ISSET( sock, &fd ) )
        {
            // 만약 이전의 accept_sock 이 남아있는 듯하면 확인사살로 close 하고 초기화
            if( accept_sock > 0 )
            {
                close(accept_sock);
                accept_sock = -1;
            }

            // listen socket 에 있는 pending 연결요청을 하나 받아들인다.
            accept_sock = svr->accept();
            if( accept_sock < 0 )
            {
                printf("accept fail...[%d] [%s]n", accept_sock, strerror(errno));
                // sleep here
                continue;
            }
            printf("accept okay...[%d]n", accept_sock );
        }

        if( FD_ISSET( accept_sock, &fd ) )
        {
            ret = svr->recv(buf);
            if( ret < 0 )
            {
                svr->close(accept_sock);
                continue;
            }
            printf("recv... ret[%d] message[%s]n", ret, buf );
        }
    }
    return 0;
}

컴파일 순서는 library directory 에서 make 한 후 LD_LIBRARY_PATH 잡아주고, test directory 에서 make 하고 실행하면 됩니다.

자… 이제 실행해 봅시다.
두근두근…. ^^

먼저 tcpsvr 먼저 실행 후 tcpcli 를 띄우면 됩니다.

sh> ./tcpsvr
open okay...[3]
accept okay...[4]
recv... ret[31] message[this is [0]th test message !!!!]
recv... ret[31] message[this is [1]th test message !!!!]
recv... ret[31] message[this is [2]th test message !!!!]
recv... ret[31] message[this is [3]th test message !!!!]
recv... ret[31] message[this is [4]th test message !!!!]
recv... ret[31] message[this is [5]th test message !!!!]
recv... ret[31] message[this is [6]th test message !!!!]
recv... ret[31] message[this is [7]th test message !!!!]
recv... ret[31] message[this is [8]th test message !!!!]
recv... ret[31] message[this is [9]th test message !!!!]
sh> ./tcpcli
open okay...[3]
[0] send... ret (31)
[1] send... ret (31)
[2] send... ret (31)
[3] send... ret (31)
[4] send... ret (31)
[5] send... ret (31)
[6] send... ret (31)
[7] send... ret (31)
[8] send... ret (31)
[9] send... ret (31)

아주 잘 동작하네요. 주고 받은 메시지 내용과 size 도 정확합니다.

이제 이 library 가 어느 정도의 성능을 보이고 응답 latency 가 얼마이고… 이런 것은 여러분이 직접 시험을 해보셨으면 좋겠네요.
clock_gettime() 이라는 함수를 사용하면 nano second 단위까지 시간을 정확하게 측정할 수 있습니다.

참고로 각기 다른 서버에서 client 가 자신이 송신한 메시지가 server 측에 갔다오는데 얼마나 걸리는지 정확하게 측정하고 싶다면, client 가 송신하는 메시지에 clock_gettime() 의 결과를 저장하여 보낸 후, server 는 이를 수신하는 즉시 그대로 client 에 전송해주면, client 는 메시지 수신 직후 다시 clock_gettime() 을 측정하여 메시지에 담긴 시간과의 차이를 구하면 됩니다.
이것이 해당 메시지가 1 round trip 을 하는데 걸린 정확한 시간이 되는 것이죠.

이제 소스 첨부를 마지막으로 tcp socket library 에 대한 강의를 마치겠습니다.
다음 시간부터는 inet udp library 를 만들어보도록 하겠습니다.

 

cfile26.uf.261D82505298FD3F249E97.gz

 

You may also like...