• Server
    - 5_server
     : 클래스로 설계

    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
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    #include <stdio.h>
    #include <string.h>
     
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
     
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    #include "Packet.h"
     
    int calculate(char op, int value1, int value2)
    {
        switch (op) {
            case '+': return value1 + value2;
            case '-': return value1 - value2;
            case '*': return value1 * value2;
     
            default:
                return -1;
        }
    }
     
    // TCP의 경계가 모호하거나, 데이터가 도달하지 않는 문제를
    // 해결하기 위해서는 readn을 도입하면 된다.
    int readn(int sd, char* buf, int len)
    {
        int n;
        int ret;
     
        n = len;
        while (n > 0)
        {
            ret = read(sd, buf, len);
            if (ret < 0) return -1;
            if (ret == 0) return len - n;
     
            buf += ret;
            n -= ret;
        }
     
        return len;
    }
     
     
     
    // 클래스를 설계할 때 지켜야하는 원칙 : SRP
     
    // 객체 지향 5대 원칙 - 로버트 C 마틴(클린 코드)
    // SRP: 단일 책임 원칙
    // OCP: 개방 폐쇄 원칙
    // LSP: 리스코프 치환 원칙
    // ISP: 인터페이스 분리 원칙
    // DIP: 의존관계 역전 원칙
     
     
    class NetAddress
    {
        sockaddr_in addr;
    public:
        NetAddress(const char* ip, short port)
        {
            memset(&addr, 0, sizeof addr);
     
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(ip);
        }
     
        sockaddr* getRawAddress()
        {
            return (sockaddr*)&addr;
        }
     
    };
     
    class Socket
    {
        int sock;
    public:
        Socket() { sock = socket(PF_INET, SOCK_STREAM, 0); }
     
        explicit Socket(int sockFd) : sock(sockFd) {}
     
        void bind(NetAddress* address)
        {
            // 다시 C 함수롤 호출해야 한다.   
            ::bind(sock, address->getRawAddress(), sizeof(sockaddr_in));
        }
     
     
        void setReuseAddress(bool b)
        {
            int option = b;
            socklen_t optlen = sizeof(option);
            setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, optlen);
        }
     
        void listen(int backlog)
        {
            ::listen(sock, backlog);
        }
     
        Socket accept()
        {
            struct sockaddr_in caddr = {0, };
            socklen_t clen = sizeof(caddr);
            int csock = ::accept(sock, (struct sockaddr*)&caddr, &clen);
     
            return Socket(csock);
        }
     
        inline int read(char* buf, size_t size)
        { return ::read(sock, buf, size); }
     
        inline int write(char* buf, size_t len)
        { return ::write(sock, buf, len); }
     
        inline int readn(char* buf, int len)
        { return ::readn(sock, buf, len); }
     
        inline int close()
        { return ::close(sock); }
     
    };
     
     
    int main()
    {
        // int sock = socket(PF_INET, SOCK_STREAM, 0);
        Socket sock;
     
        NetAddress address("0.0.0.0", 4000);
        // struct sockaddr_in saddr = {0, };
        // saddr.sin_family = AF_INET;
        // saddr.sin_port = htons(4000);
        // saddr.sin_addr.s_addr = INADDR_ANY; // 0.0.0.0
     
        sock.setReuseAddress(true);
        // int option = true;
        // socklen_t optlen = sizeof(option);
        // setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, optlen);
     
        sock.bind(&address);
        // bind(sock, (struct sockaddr*)&saddr, sizeof saddr);
     
        sock.listen(5);
        // listen(sock, 5);
     
        while (1)
        {
     
            Socket csock = sock.accept();
            // struct sockaddr_in caddr = {0, };
            // socklen_t clen = sizeof(caddr);
            // int csock = accept(sock, (struct sockaddr*)&caddr, &clen);
     
            // char* cip = inet_ntoa(caddr.sin_addr);
            // printf("Connected from %s\n", cip);
     
            while (1)
            {
                int len;
                int ret = csock.readn((char*)&len, sizeof(len));
     
                printf("len : %d\n", len);
                if (ret != sizeof len) {
                    break;
                } else if (ret == -1) {
                    perror("readn()");
                    break;
                }
     
                char buf[4096];
                ret = csock.readn(buf, len);
                if (ret != len) {
                    break;
                } else if (ret == -1) {
                    perror("readn()");
                    break;
                }
     
                // 이제 데이터를 파싱하면 됩니다.
                Packet packet(buf);
                char op = packet.getByte();
                int value1 = packet.getInt32();
                int value2 = packet.getInt32();
     
                printf("%2d%2c%-2d\n", value1, op, value2);
                int result = calculate(op, value1, value2);
     
                csock.write((char*)&result, sizeof(result));
            }
     
            //-----------------
            csock.close();
        }
     
        sock.close();
    }


    - 6_server
     : SRP - Facade Pattern 적용

    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
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    #include <stdio.h>
    #include <string.h>
     
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
     
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    #include "Packet.h"
     
    int calculate(char op, int value1, int value2)
    {
        switch (op) {
            case '+': return value1 + value2;
            case '-': return value1 - value2;
            case '*': return value1 * value2;
     
            default:
                return -1;
        }
    }
     
    // TCP의 경계가 모호하거나, 데이터가 도달하지 않는 문제를
    // 해결하기 위해서는 readn을 도입하면 된다.
    int readn(int sd, char* buf, int len)
    {
        int n;
        int ret;
     
        n = len;
        while (n > 0)
        {
            ret = read(sd, buf, len);
            if (ret < 0) return -1;
            if (ret == 0) return len - n;
     
            buf += ret;
            n -= ret;
        }
     
        return len;
    }
     
     
     
    // 클래스를 설계할 때 지켜야하는 원칙 : SRP
     
    // 객체 지향 5대 원칙 - 로버트 C 마틴(클린 코드)
    // SRP: 단일 책임 원칙
    // OCP: 개방 폐쇄 원칙
    // LSP: 리스코프 치환 원칙
    // ISP: 인터페이스 분리 원칙
    // DIP: 의존관계 역전 원칙
     
     
    class NetAddress
    {
        sockaddr_in addr;
    public:
        NetAddress(const char* ip, short port)
        {
            memset(&addr, 0, sizeof addr);
     
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(ip);
        }
     
        sockaddr* getRawAddress()
        {
            return (sockaddr*)&addr;
        }
     
    };
     
    class Socket
    {
        int sock;
    public:
        Socket() { sock = socket(PF_INET, SOCK_STREAM, 0); }
     
        explicit Socket(int sockFd) : sock(sockFd) {} // explicit로 지정함으로써 암시적 형변환을 막는다.
     
        void bind(NetAddress* address)
        {
            // 다시 C 함수롤 호출해야 한다.   
            ::bind(sock, address->getRawAddress(), sizeof(sockaddr_in));
        }
     
     
        void setReuseAddress(bool b)
        {
            int option = b;
            socklen_t optlen = sizeof(option);
            setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, optlen);
        }
     
        void listen(int backlog)
        {
            ::listen(sock, backlog);
        }
     
        Socket accept()
        {
            struct sockaddr_in caddr = {0, };
            socklen_t clen = sizeof(caddr);
            int csock = ::accept(sock, (struct sockaddr*)&caddr, &clen);
     
            return Socket(csock);
        }
     
        inline int read(char* buf, size_t size)
        { return ::read(sock, buf, size); }
     
        inline int write(char* buf, size_t len)
        { return ::write(sock, buf, len); }
     
        inline int readn(char* buf, int len)
        { return ::readn(sock, buf, len); }
     
        inline int close()
        { return ::close(sock); }
     
    };
     
    // TCP 서버 프로그래밍을 하는데 있어서 필요한 클래스와 절차를
    // 단순화 시켜주는 상위 개념의 클래스를 제공하자.
    // -> Facade Pattern
     
    class TCPServer
    {
        Socket sock;
    public:
        void start(short port)
        {
            NetAddress address("0.0.0.0", port);
            sock.setReuseAddress(true);
            sock.bind(&address);
            sock.listen(5);
     
            while (1)
            {
     
                Socket csock = sock.accept();
     
                while (1)
                {
                    int len;
                    int ret = csock.readn((char*)&len, sizeof(len));
     
                    printf("len : %d\n", len);
                    if (ret != sizeof len) {
                        break;
                    } else if (ret == -1) {
                        perror("readn()");
                        break;
                    }
     
                    char buf[4096];
                    ret = csock.readn(buf, len);
                    if (ret != len) {
                        break;
                    } else if (ret == -1) {
                        perror("readn()");
                        break;
                    }
     
                    // 이제 데이터를 파싱하면 됩니다.
                    Packet packet(buf);
                    char op = packet.getByte();
                    int value1 = packet.getInt32();
                    int value2 = packet.getInt32();
     
                    printf("%2d%2c%-2d\n", value1, op, value2);
                    int result = calculate(op, value1, value2);
     
                    csock.write((char*)&result, sizeof(result));
                }
     
                //-----------------
                csock.close();
            }
     
            sock.close();
     
     
        }
     
    };
     
     
    int main()
    {
        TCPServer server;
        server.start(4000);
    }


+ Recent posts