ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TCP/IP] 소켓 옵션을 사용해보자 (슬라이딩 윈도우 제어)
    C_C++ 프로그래밍/TCP_IP 2019. 6. 21. 01:59

     

         로재의 개발 일기      




    슬라이딩 윈도우가 뭔데요?

    간단히 말해서 데이터를 전송하기 위한 가상의 공간을 말하며

    이는 데이터 전송 및 수신에 큰 영향을 미칩니다.

    내부적으로는 여러가지 일들이 돌아가고 좀 더 복잡하죠.


    혹시 필요하시면 슬라이딩 윈도우에 관해서 쓴 글을 참고하시면 좋을 거 같습니다.

    슬라이딩 윈도우란??




    파일 전송?

    위에서 슬라이딩 윈도우를 조절하면 데이터 전송에 상당한 영향을 끼친다고 말했습니다.

    하지만, 확실하게 예제를 통해서 육안으로 확인을 해보면 좋겠다.. 라는 생각이 들어서

    파일 전송 프로그램을 사용하여, 걸리는 시간을 확인해봤습니다.


    (미구현) 추가적으로 걸리는 시간 출력도 구현하면 좋겠다는 생각이 드네요.

    혹시 적당한 파일이 없으신 분들은

    매우 큰 텍스트 파일 만들기

    위 글을 참고하시면 좋을 것 같습니다.



      file_trans_server.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <fcntl.h>
     
    #define MAXLINE 127
     
    int main(int argc, char *argv[])
    {
        struct sockaddr_in servaddr, cliaddr;
        int listen_sock, accp_sock, // 소켓번호
        addrlen = sizeof(cliaddr), // 주소구조체 길이
        nbyte, nbuf;
        char buf[MAXLINE+1];
        char cli_ip[20];
        char filename[20];
        int filesize=0;
        int total=0, sread, fp;
     
        if(argc != 2) {
            printf("usage: %s port ", argv[0]);
            exit(0);
        }
        // 소켓 생성
        if((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
            perror("socket fail");
            exit(0);
        }
     
        // servaddr을 ''으로 초기화
        bzero((char *)&servaddr, sizeof(servaddr));
        // servaddr 세팅
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(atoi(argv[1]));
     
        // bind() 호출
        if(bind(listen_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
            perror("bind fail");
            exit(0);
        }
     
        // 소켓을 수동 대기모드로 세팅
        listen(listen_sock, 5);
     
        while(1)
        {
            puts("서버가 연결요청을 기다림..");
            // 연결요청을 기다림
            accp_sock = accept(listen_sock,(struct sockaddr *)&cliaddr, &addrlen);
     
            if(accp_sock < 0)
            {
                perror("accept fail");
                exit(0);
            }
     
            puts("클라이언트가 연결됨..");
        
            inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, cli_ip, sizeof(cli_ip));
            printf"IP : %s ", cli_ip );
            printf"Port : %x ", ntohs( cliaddr.sin_port) );
     
            bzero( filename, 20 );
            recv( accp_sock, filename, sizeof(filename), 0 );
            printf"%s ", filename );
     
            // recv( accp_sock, &filesize, sizeof(filesize), 0 );
            read( accp_sock, &filesize, sizeof(filesize) );
            printf"%d ", filesize );
     
            strcat( filename, "_backup" );
            fp = open( filename, O_WRONLY | O_CREAT | O_TRUNC);
     
            // slidng window control section
            int buf_size = 0;
            int opt_len;
     
            opt_len = sizeof(int);
            if(getsockopt(accp_sock, SOL_SOCKET, SO_SNDBUF, (void *&buf_size, &opt_len) < 0){
                    printf("get socket option error\n");
                    return 0;
            }
            
            buf_size = 128;
            if(setsockopt(accp_sock, SOL_SOCKET, SO_RCVBUF, (void *&buf_size, sizeof(int)) < 0){
                    printf("set socket option error\n");
                    return 0;
            }
            // section end
     
            while( total != filesize )
            {
                sread = recv( accp_sock, buf, 1000 );
                printf"file is receiving now.. \n" );
                total += sread;
                buf[sread] = 0;
                write( fp, buf, sread );
                bzero( buf, sizeof(buf) );
                printf"processing : %4.2f%% \n", total*100 / (float)filesize );
            }
            printf"file traslating is completed " );
            printf"filesize : %d, received : %d ", filesize, total );
     
            close(fp);
            close(accp_sock);
        }
        close( listen_sock );
        return 0;
    }
    cs


      file_trans_client.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h>
     
    #define MAXLINE 127
     
    int main(int argc, char **argv )
    {
        struct sockaddr_in servaddr;
        int s, nbyte;
        char buf[MAXLINE+1];
        char filename[20];
        int filesize, fp, filenamesize ;
        int sread, total=0;
     
        if(argc != 3)
        {
            printf("usage: %s ip_address port ", argv[0]);
            exit(0);
        }
     
        if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("socket fail");
            exit(0);
        }
     
        // 에코 서버의 소켓주소 구조체 작성
        bzero((char *)&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
        servaddr.sin_port = htons(atoi(argv[2]));
     
        // 연결요청
        if(connect(s, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
        {
            perror("connect fail");
            exit(0);
        }
     
        printf("select file to send : ");
        if ( fgets(filename, sizeof(filename), stdin) == NULL )
            exit(0);
     
        filenamesize = strlen(filename);
        filename[filenamesize-1= 0;
     
        if( (fp = open( filename, O_RDONLY )) < 0 )
        {
            printf"open failed" );
            exit(0);
        }
     
        send( s, filename, sizeof(filename), 0 );
     
        filesize = lseek( fp, 0, SEEK_END );
        send( s, &filesize, sizeof(filesize), 0 );
        lseek(fp, 0, SEEK_SET );
        
        // sliding window control section 
        int buf_size = 0;
        int opt_len;
     
        opt_len = sizeof(int);
        if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *&buf_size, &opt_len) < 0){
                printf("get socket option error\n");
                return 0;
        }
     
        buf_size = 128;
        if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *&buf_size, sizeof(int)) < 0){
                printf("set socket option error\n");
                return 0;
        }
        // section end
     
        while( total != filesize )
        {
            sread = read( fp, buf, 100 );
            printf"file is sending now.. \n" );
            total += sread;
            buf[sread] = 0;
            send( s, buf, sread, 0 );
            printf"processing :%4.2f%% \n", total*100 / (float)filesize );
        }
        printf"file translating is completed " );
        printf"filesize : %d, sending : %d ", filesize, total );
     
        close(fp);
        close(s);
        return 0;
    }
    cs




    마무리

    소켓 함수의 옵션의 윈도우 크기를

    default 값이 아닌 128이라는 작은 값으로 수정한 결과

    1초도 안 걸리는 데이터가 2-3분 가량 걸렸습니다.


    혹시 직접 확인하실 분들은

    // sliding window section 부터

    // end 부분까지 삭제하시고


    삭제하기 전과 후를 비교하시면 되겠습니다.


    참고



    ※ 본 글은 개인 포트폴리오 혹은 공부용으로 사용하기 때문에, 무단 복사 유포는 금지하지만, 개인 공부 용도로는 얼마든지 사용하셔도 좋습니다





    반응형
Designed by Tistory.