Server
- 5_server
: 클래스로 설계
#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 적용
#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); }
'Programing > Server Model' 카테고리의 다른 글
서버 모델 - Synchronous Blocking I/O (0) | 2016.02.22 |
---|---|
서버 모델 - I/O 모델 개요 (0) | 2016.02.22 |
서버 모델 - 리눅스 소켓 프로그래밍(2) (0) | 2016.02.18 |
서버 모델 - 리눅스 소켓 프로그래밍(1) (0) | 2016.02.18 |
서버 모델 - 소켓 프로그래밍 (0) | 2016.02.18 |