• 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);
    }
    


+ Recent posts