Server
- 5_server
: 클래스로 설계
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201#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 적용
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198#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 |