SlideShare ist ein Scribd-Unternehmen logo
1 von 59
Downloaden Sie, um offline zu lesen
TCP/IP Review
&
IO Model
NHN NEXT
남현욱
01
nagle algorithm
“가능하면 조금씩 여러 번 보내지 말고 한 번에 많이 보내라”
01 nagle algorithm
•	왜 필요한가?
패킷은 보낼 때마다 고정적인 비용(packet header)이 필요하다. 작은 크기의 패킷을 여러 번
보낼 경우 이 고정 비용때문에 네트워크 자원을 그만큼 더 많이 쓰게 된다. 이걸 버퍼에 모아두었
다가 되도록 묶어서 한 번에 보냄으로써 네트워크 자원을 효율적으로 쓰는 것이다.
•	게임에서는?
Nagle 알고리즘을 쓰면 네트워크 자원을 효율적으로 쓸 수 있긴 하지만 반대로 응답 속도가 안
좋아지게 된다. 그 때 그 때 보내는 게 아니라 모아서 보내기 때문. 따라서 반응 속도가 중요한 게
임의 경우 Nagle 알고리즘을 쓰지 않는게 좋을 때도 많다.
물론 항상 그렇듯이 case by case이기 때문에, 항상 Nagle을 쓰는게 좋고 항상 Nagle을 안 쓰
는게 좋고 이렇게 이야기할 수는 없다. 자신이 처한 상황에 따라 쓸 지 안 쓸 지 적절히 선택하는
게 좋다.
01 nagle algorithm
•	동작 원리
Host A Host B Host A Host B
Nagle OFF Nagle ON
ACK
ACK
ACK
ACK
ACK
N
A
G
L
E
N
ACK
ACK
AGLE
01 nagle algorithm
•	C++에서의 구현
int opt = true;
setsockopt(socket, IPPROTO_TCP,
TCP_NODELAY, (const char*)&opt, sizeof(int));
Nagle 알고리즘은 기본적으로 ON되어 있다. 그래서 Nagle 알고리즘을 쓰지 않고 싶을 경우 위
코드를 이용해 Nagle 알고리즘의 사용을 해제할 수 있다.
- setsockopt : 소켓의 옵션을 변경하기 위해 사용되는 함수다. 인자로 소켓 / 소켓의 레벨 /
지정할 옵션 / 옵션 값을 지정하기 위한 포인터 / 옵션 값의 크기 를 받는다.
- IPPROTO_TCP  : soket의 레벨 값으로는 IPPROTO_TCP와 SOL_SOCKET 두 가지가 있
다. 어떤 레벨이냐에 따라 지정가능한 옵션이 다른데 IPPROTO_TCP로 해야 Nagle 알고리즘 사
용여부 옵션을 바꿀 수 있다.
- TCP_NODELAY : 이름에서도 알 수 있듯이 이 옵션 값을 1로 하면(적용시켜주면) Nagle 알
고리즘이 꺼진다.
02
TCP States
“단절을 감지하고, 우아하게 연결을 끊는 방법은?”
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
3way-
handshaking
과정을 통한
서버-클라이언트
연결 시작
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
SYN
RECEIVED
SYN/SYN+ACK
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
SYN
RECEIVED
SYN/SYN+ACK
ESTABLISHED
SYN+ACK/SYN
클라이언트
성공적으로
연결 완료!
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
SYN
RECEIVED
SYN/SYN+ACK
ESTABLISHED
SYN+ACK/SYN
ESTABLISHED
ACK
서버도
성공적으로
연결 완료!
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
SYN
RECEIVED
SYN/SYN+ACK
ESTABLISHED
SYN+ACK/SYN
ESTABLISHED
ACK
이제 서로 데이터를 주고
받는다.
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
SYN
RECEIVED
SYN/SYN+ACK
ESTABLISHED
SYN+ACK/SYN
ESTABLISHED
ACK
이 때 데이터를 주고 받다
가 한 쪽에서 연결이 끊어
지면?
비정상적인
연결 끊김!
02 TCP States
•	유령 세션은 왜 생기나?
Server Client
CLOSED CLOSED
LISTEN
LISTEN
SYN
SENT
CONNECT/SYN
SYN
RECEIVED
SYN/SYN+ACK
ESTABLISHED
SYN+ACK/SYN
ESTABLISHED
ACK
정상적 종료가 아니면 왜
데이터가 안 오는 지 알
수 없으므로 올 때까지 기
다린다!
WAIT...
02 TCP States
•	유령 세션은 왜 생기나?
아까 전 그림처럼 정상적으로 ‘연결이 종료되었음’이라는 메시지 없이 연결이 비정상적으로 끊
겼을 경우 무한히 대기하게 된다. 어떤 네트워크 사정때문에 데이터의 전송이 늦어지는 건지 아
니면 연결에 문제가 있는 건지 알 수 없기 때문이다. 이 때문에 유령 세션이 발생하게 된다.
•	해결 방법
TCP 특성 상 깔끔하게 해결하기는 쉽지 않다.
heartbeat : 심장 박동처럼 일정 주기로 서버와 클라이언트가 패킷을 주고 받으면서 서로 살아
있는지 검사하는 방법이다.
keepalive : 소켓에서 자체적으로 heartbeat처럼 검사하는 방법이다. 일정 시간을 설정한 다음
그 시간을 넘으면 검사 패킷을 보내고 일정 이상 응답이 오지 않으면 연결을 종료시킨다.
02 TCP States
•	TCP_LINGER 옵션
소켓의 연결을 종료할 때 미처 전송되지 못하고 버퍼에 남아있는 데이터를 어떻게 처리할 것인지
결정하기 위한 옵션이다. l_onoff와 l_linger 두 가지 옵션이 있다. l_onoff는 linger 옵션을 사
용할 건지 말 건지를 결정한다. 기본적으로는 linger 옵션 사용 안하고, close 호출 시 내부적으
로 정상적인 종료 과정을 진행한다.
l_onoff = 1,  l_linger = 0
closesocket() 즉시 리턴. 버퍼에 남아 있는 데이터는 모두 파기한다.
l_onoff = 1, l_linger > 0
일단 정상적인 종료 과정(Graceful Shutdown)을 진행하되, 지정한 시간(l_linger)이 지나도
제대로 완료되지 않으면 무시하고 위와 마찬가지로 즉시 연결 종료 후 남은 데이터는 파기시킨
다.
02 TCP States
•	TCP_LINGER 옵션
사용법 코드 예제
//Linger 옵션 지정용 구조체
LINGER ling = {0, };
ling.l_onoff = 1; //LINGER 옵션 사용
ling.l_linger = 0; //몇 초 기다릴 지 시간 설정
//LINGER 옵션 특정 소켓에 적용.
setsockopt(socket, SOL_SOCKET, SO_LINGER, (CHAR*)&ling, sizeof(ling));
// 해당 옵션이 적용된 socket 종료 과정 수행.
closesocket(socket);
02 TCP States
•	Graceful Shutdown
데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정.
ServerClient
ESTABLISHED ESTABLISHED
02 TCP States
•	Graceful Shutdown
데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정.
ServerClient
ESTABLISHED ESTABLISHED
FIN
FIN_WAIT_1 CLOSE_WAIT연결 종료를 시작한다는
의미로 Client에서 FIN을
보낸다.
02 TCP States
•	Graceful Shutdown
데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정.
ServerClient
ESTABLISHED ESTABLISHED
FIN
FIN_WAIT_1 CLOSE_WAIT
ACK
FIN_WAIT_2 Server는 그에 대한 응답
을 보내고 연결을 종료하
기 위한 준비를 한다.
02 TCP States
•	Graceful Shutdown
데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정.
ServerClient
ESTABLISHED ESTABLISHED
FIN
FIN_WAIT_1 CLOSE_WAIT
ACK
FIN_WAIT_2 LAST_ACK
FIN
TIME_WAIT 준비가 끝나면 client에
FIN을 보내 연결을 종료
할 것임을 알린다.
02 TCP States
•	Graceful Shutdown
데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정.
ServerClient
ESTABLISHED ESTABLISHED
FIN
FIN_WAIT_1 CLOSE_WAIT
ACK
FIN_WAIT_2 LAST_ACK
FIN
TIME_WAIT
CLOSED
FIN을 받아도 Client는 종료되지 않고 한동안
TIME_WAIT가 된다. 네트워크 문제로 FIN보
다 늦게 도착하는 패킷이 존재할 수 있기 때문.
ACK
02 TCP States
•	Graceful Shutdown
데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정.
ServerClient
ESTABLISHED ESTABLISHED
FIN
FIN_WAIT_1 CLOSE_WAIT
ACK
FIN_WAIT_2 LAST_ACK
FIN
TIME_WAIT
CLOSED
ACK
CLOSED 이렇게 일정 시간이
지나면 종료시킴.
02 TCP States
•	Graceful Shutdown
Graceful Shutdown에서 주의해야할 점은 다음과 같다.
1. TIME_WAIT는 먼저 종료를 시작한 쪽에서 생긴다.
Graceful Shutdown과정에서 TIME_WAIT가 생기는 건 불가피한 일이다. 하지만 TIME_
WAIT단계가 서버에서 발생한다면 서버 부하의 원인이 될 수 있으므로 꼭 클라이언트에서 종료
를 시작하게 만들자.
2. Server에서 TIME_WAIT가 안 생기게 하는 법
•	서버에서 클라이언트에 종료하라는 커맨드를 보낸다
•	수신한 클라이언트는 종료하겠다 전송 후 closesocket() 수행
•	클라이언트의 종료하겠다는 메시지 받은 서버는 해당 소켓에 대해 closesocket() 호출. 이
때 linger 옵션을 이용해 혹시 모를 TIME_OUT을 막음(어차피 서버에서 클라이언트로 보낼
데이터는 없을게 확실하기 때문에 linger 옵션을 사용)
03
IO Model
“다양한 네트워크 IO 모델의 장단점을 알아보자”
03 IO Model
•	Synchronous Vs Asynchronous
Synchronous(동기)
작업을 요청한 후 해당 작업의 결과가 나올 때까지 기다린 후 처리하는 것 .
IO 작업에 대한 readiness를 기다린다. 특정 IO 작업을 하기 위한 준비가 되었는 지에 집중. 그
런 이벤트의 발생을 기다렸다가 그 이벤트가 발생하면 그에 따른 적합한 처리를 한다.
Asynchronous(비동기)
작업을 요청해놓고 딴 일을 하다가 해당 작업이 완료되면 그 때 완료되었음을 통지 받고 그에 따
른 처리를 하는 것이다.
IO 작업의 completion을 기다린다. 운영체제 단계의 비동기 API를 통해 이루어지며 IO 작업이
completion되면 그에 적합한 Handler를 이용해 처리를 한다.
03 IO Model
•	Blocking Vs Non-blocking
I/O 작업에서 Blocking으로 동작할 경우 해당 I/O가 끝날 때까지 대기해야하고(I/O가 끝나기
전에는 함수가 반환되지 않는다), Non-Blocking으로 동작할 경우 작업을 완료할 수 있다면 완
료하고 그렇지 못한 상황이라면 대기하지 않고 리턴해버린다.
Socket에서의 Non-Blocking 설정
ULONG isNonblocking = 1;
ioctlsocket(socket, FIONBIO, &isNonBlocking);
ioctlsocket : 특정 socket의 I/O 상태를 바꿀 때 사용하는 함수다.
FIONBIO : 3번째 인자로 넘어온 속성 값이 0이면 Blocking, 0이 아니면 non-blocking으로
설정한다.
&isNonBlocking : 속성 값을 지정한 변수의 주소를 넘긴다.
03 IO Model
•	Blocking Vs Non-blocking
Non-Blocking Socket의 IO
non-blocking socket에서 데이터를 전부 받으려면 아래처럼 해야한다
for (;;)
{
	 if (recvLen = recv(socket, str + length, strLen, 0) < 0)
	{
		if (WSAGetLastError() == WSAEWOULDBLOCK)
			Sleep(1000); // 기다림
	}
	 else
	{
		 length += recvLen;
		if (length >= strLen)
			break;
	}
}
recvLen은 이번에 받은 양, strLen은 받고자 하는 길이, length는 받은 양의 누적 합이다.
non-blocking은 recv를 호출해도 바로 리턴되기 때문에 데이터를 끝까지 읽지 못했거나 하나
도 못 읽은 경우가 발생할 수 있다. 따라서 recv 호출 후에 얼만큼 읽었는지, 현재 socket의 상태
가 어떤 지 확인하고 그에 따른 처리를 해 줘야 한다.
03 IO Model
•	IO 이벤트 통지 모델
구세대 네트워크 I/O 방식
Server
Thread1
Thread2
Thread3
Thread4
Client1
Client2
Client3
Client4
접속한 각각의 클라이언
트 별로 Thread를 하나씩
두고 따로 처리하게 만든
다. 이용자 수가 많을 수록
Thread간의 컨텍스트 스
위칭 비용이 커진다.
I/O 이벤트 통지 모델이 필요한 이유
이벤트 통지 모델을 이용하면 Thread 개수를 훨씬 줄일 수 있다. 동시 접속자 수가 많을 수록 이
벤트 통지 모델을 이용하는 편이 성능이 좋을 것이다.
03 IO Model
•	SELECT
SELECT는 이벤트 별로 감시할 소켓들을 등록하고(fd_set), 등록된 소켓에 뭔가 이벤트가 발생
했을 경우 그걸 확인하는 방식으로 동작한다.
int select(int nfds, fd_set* readfds, fd_set* writefds,
fd_set* errorfds, struct timeval* timeout);
첫 번째 인자로 검사할 fd(file descriptor)의 개수를 설정한다. 0~fd-1까지를 검사한다.
readfds, writefds, errorfds는 각각의 이벤트에 대해 검사할 소켓의 목록을 저장한 비트필드
의 포인터이다(nullptr이면 해당 이벤트는 체크 안함). fd_set을 만들기 위해 다음과 같은 함수
들을 이용한다.
void FD_ZERO(fd_set* fdset) : 해당 fd_set의 값을 모두 0으로 초기화한다.
void FD_CLR(int fd, fd_set* fdset) : 해당 fd_set에서 fd에 해당하는 비트를 0으로 만든다.
void FD_SET(int fd, fd_set* fdset) : 해당 fd_set에서 fd에 해당하는 비트를 1로 만든다.
void FD_ISSET(int fd, fd_set* fdset) : fd_set에서 fd에 해당하는 비트가 1인지 검사한다.
03 IO Model
•	SELECT
예제 코드
FD_ZERO(&readsets);
while (true)
{
	 FD_SET(socket, &readsets);
	 n = select(max_fd + 1, &readsets, nullptr, nullptr, nullptr);
	 if (n < 0) //error 처리
		return -1;
	 for (int i = 0; i < max_fd; i++)
	{
		if (FD_ISSET(i, &readsets))
		{
			// ... recv, accept 등 처리
		}
	}
}
03 IO Model
•	SELECT
장점
지원하는 OS가 많아 이식성이 좋다(POSIX 표준).
단점
검사할 수 있는 fd 개수에 제한이 있다(최대 1024개).
매번 검사할 때마다 루프로 전체 fd를 다 검사해야하기 때문에 속도가 느리다.
Async / Sync, Blocking / Non-blocking ?
OS 레벨에서 비동기로 IO 작업을 하며 IO가 끝났음을 통지 받아서 처리하는 것이 아니라 자
체적인 event loop를 통해 매번 소켓의 상태가 변했는지 확인한 뒤 그에 따른 처리를 하므로
Synchronous.
timeout을 nullptr로 설정하면 뭔가 이벤트가 발생할 때까지 진행하지 않는다. 따라서 이 경우
는 Blocking이다. timeout를 설정할 경우 해당 시간이 지나면 아무 이벤트가 발생하지 않아도
넘어가므로 Non-blocking이 된다.
03 IO Model
•	EPOLL
select의 단점을 개선한 것이다. select가 매번 모든 fd를 다 검사해야하는 반면 epoll은 검사할
fd만 등록해 놓으면 커널이 그 fd들을 관리하면서 이벤트 발생 여부를 알려주기 때문에 더 효율
이 뛰어나다.
epoll_create(int size)
epoll을 위한 인스턴스를 생성한 뒤 그 fd를 돌려준다.
epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
epoll에 이벤트 등록 등의 일을 담당하는 함수다. epfd: epoll_create로 받은 epoll 인스턴스
의 fd. op : 어떤 동작을 할 지 결정. EPOLL_CTL_ADD는 epoll 인스턴스에 감시할 fd 추가,
EPOLL_CTL_MOD는 등록된 fd와 연관된 event 변경, EPOLL_CTL_DEL은 등록된 fd의 삭
제. 마지막 인자는 어떤 이벤트를 통지 받을 지 구조체를 정해 넘긴다.
epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)
epoll_create로 만든 인스턴스의 번호를 넘기면 이벤트가 발생할 때까지 지정한 시간 만큼 기
다렸다가 이벤트가 발생한 fd들을 반환한다.
03 IO Model
•	EPOLL
예제 코드
epollfd = epoll_create(10); //epoll 인스턴스 생성
if (epollfd == -1) return -1;
ev.envents = EPOLLIN; //읽을 수 있는 지(accept)
ev.data.fd = listenSock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenSock, &ev) == -1)
	 return -1;
while (true){
	 if ((nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1)) == -1)
		return -1;
	 for (n = 0; n < nfds; ++n){
		if (events[n].data.fd == listenSock){
			connSock = accept(listen_sock, (struct sockaddr *) &local, &addrlen);
			if (connSock == -1) return -1;
			setnonblocking(connSock); // 논블로킹 설정
			ev.events = EPOLLIN | EPOLLET;
			ev.data.fd = connSock;
			//accept된 socket도 epoll에 추가(recv 이벤트 통지).
			if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connSock, &ev) == -1)
				return -1;
		}
		else
			do_use_fd(events[n].data.fd); //읽은 데이터 처리
	}
}
03 IO Model
•	EPOLL
장점
select와는 다르게 관리할 수 있는 fd 개수의 제한이 없다.
관리할 fd를 한 번만 등록하면 커널에서 관리하며 이벤트가 발생한 것만 넘겨주므로 루프 돌 때
마다 매 번 검사해야하는 select보다 훨씬 효율적이다.
단점
리눅스 커널 2.6 이상에서만 지원하므로 이식성이 떨어진다.
Async / Sync, Blocking / Non-blocking ?
Select와 마찬가지 이유로 Synchronous.
Select와 마찬가지로 timeout을 nullptr로 설정하면 뭔가 이벤트가 발생할 때까지 진행하지
않는다. 따라서 이 경우는 Blocking이고, timeout를 설정할 경우 Non-Blocking이 된다.
03 IO Model
•	WSAAsyncSelect
특정 소켓에 대해 통지 받을 이벤트와 통지 받을 때 사용할 메시지를 지정해주면 해당 이벤트가
생길 때 메시지 큐를 이용해 윈도우 메시지의 형태로 통지해주는 방식이다.
WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent)
s : 이벤트를 통지받을 소켓.
hWnd : 메시지를 보낼 윈도우의 핸들.
wMsg : 해당 이벤트를 통지할 때 사용할 윈도우 메시지 값이다.
lEvent : 통지 받을 이벤트. 주로 사용되는 값으로 FD_ACCEPT, FD_READ, FD_WRITE,
FD_CONNECT, FD_CLOSE등이 있다.
03 IO Model
•	WSAAsyncSelect
예제 코드
int main()
{
	...
	 WSAAsyncSelect(socket, hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
	...
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	 switch(wMsg)
	{
	 case WM_SOCKET:
		switch(WSAGETSELECTEVENT(lParam))
		{
		case FD_READ:
			...
			break;
		case FD_WRITE:
			...
			break;
		}
		break;
	}
}
03 IO Model
•	WSAAsyncSelect
장점
소켓 이벤트를 윈도우 메시지 형태로 전달 받을 수 있다. 다른 메시지 처리하듯이 일관성 있게 처
리 가능하므로 편리하다.
단점
윈도우 메시지 큐 기반이므로 사용하지 않더라도 윈도우를 반드시 띄워야 한다.
하나의 윈도우에서 윈도우 메시지와 소켓 메시지를 동시에 처리해야하므로 성능이 저하될 수 있
다.
Async / Sync, Blocking / Non-blocking ?
특정 IO 작업이 완료되면 운영체제가 그때 그때 메시지를 보내주기 때문에 Asyncronous이다.
WSAAsyncSelect 함수를 호출하면 해당 socket이 자동으로 non-blocking으로 바뀐다. 따
라서 이 socket에 대한 IO 작업도 non-blocking으로 이루어지므로 non-blocking이다.
03 IO Model
•	WSAEventSelect
WSAAsyncSelect가 메시지 형태로 처리하는 것과는 다르게 특정 네트워크 이벤트가 발생했을
때 이와 연동시킬 이벤트 오브젝트를 등록하는 방식으로 처리된다.
WSAEVENT WSACreateEvent()
이벤트 객체를 생성해서 돌려준다.
int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents)
소켓과 이벤트 객체를 짝짓는다. s는 이벤트를 감지할 소켓, hEventObject는 해당 결과를 통지
받기 위한 이벤트 객체의 핸들, lNetworkEvents는 감지할 이벤트의 종류다.
WSAAsyncSelect와 동일하게 FD_READ, FD_WRITE, FD_ACCEPT, FD_CLOSE 등등의 값
을 이용한다.
DWORD WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT *
lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable)
이벤트가 발생할 때까지 기다린다.이벤트 개수, 이벤트들의 배열, 전체 이벤트 배열의 signal이
바뀔 때까지 기다릴지 여부, 타임 아웃 시간, alertable state 설정 여부 등을 지정한다.
03 IO Model
•	WSAEventSelect
예제 코드
//event 생성 및 설정
eventArray[0] = WSACreateEvent();
...
WSAEventSelect(sockets[0], eventArray[0], FD_READ | FD_CLOSE);
while(true)
{
	 index = WSAWaitForMultipleEvents(totalEvent, eventArray,
										 false, WSA_INFINITE, false);
	 index = index - WSA_WAIT_EVENT_0;
	 WSAEnumNetworkEvents(sockets[index], eventArray[index], &netEvents);
	 //각 이벤트에 맞는 처리.
	 if(netEvents.lNetworkEvents & FD_READ)
	{
		...
	}
	 if(netEvents.lNetworkEvents & FD_CLOSE)
	{
		...
	}
}
03 IO Model
•	WSAEventSelect
장점
무조건 윈도우를 만들어줘야 하는 WSAAsyncSelect와는 다르게 윈도우를 만들어 주지 않아
도 사용 가능하다.
단점
WaitForMultipleObject에서 처리가능한 최대 이벤트 개수가 64개다. 그 이상 처리를 위해서
는 스레드를 늘려야한다.
WaitForMultipleObject가 한 번에 여러 개 이벤트가 왔을 경우 배열에서 가장 앞 인덱스를 돌
려준다. 이것만 처리하면 뒤쪽 이벤트는 잘 처리가 안 될 수 있으므로 배열의 다른 인덱스들도 확
인을 해 주어야 한다.
Async / Sync, Blocking / Non-blocking ?
Select와 비슷하게 폴링하는 방식이므로 Synchronous이다.
WSAEventSelect도 WSAAsyncSelect와 마찬가지로 소켓을 자동으로 non-blocking으로
바꾼다. 따라서 non-blocking이다.
03 IO Model
•	Overlapped I/O Callback
WSASend, WSARecv를 할 때 Overlapped 구조체 설정을 통해 I/O를 중첩시킬 수 있다. 완
료 루틴 함수까지 인자로 넘겨주면 해당 I/O 작업이 끝나고 난 뒤 완료 루틴 함수를 호출해준다.
WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD
lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
여기서 처음 5개 인자는 일반적인 recv/ send 함수와 별반 다를 바 없다.
중요한 건 lpOverlapped 인자와 lpCompletionRoutine 인자이다. lpOverlapped 인자로
WSAOVERLAPPED 구조체의 주소값을 넘기는데, 이 구조체에 I/O 작업이 끝났음을 통지하기
위한 이벤트를 등록해서 넘긴다. lpCompletionRoutine 인자로는 I/O 작업이 끝났을 때 수행
할 함수의 주소를 넘긴다. 그러면 I/O 작업이 끝난 다음 APC 큐에 들어가서 하나씩 완료 루틴 함
수를 수행하게 된다.
03 IO Model
•	Overlapped I/O Callback
예제 코드
//완료 루틴 함수
void WINAPI IOCompletionRoutine(DWORD dwError, DWORD cbTransferred,
						LPOVERLAPPED lpOverlapped, DWORD dwFlags);
WSAOVERLAPPED overlapped;
WSABUF dataBuf;
char buffer[DATA_BUFSIZE] = { 0, };
overlapped.hEvent = WSACreateEvent();
dataBuf.len = DATA_BUFSIZE;
dataBuf.buf = buffer;
WSASend(socket, &dataBuf, &sendBytes, 0, &overlapped, IOCompletionRoutine);
//다른 작업 수행
...
SleepEx(INFINITE, true);
03 IO Model
•	Overlapped I/O Callback
장점
사용자가 지정한 버퍼로 바로 복사가 일어나기 때문에 데이터 복사 비용이 줄어든다.
단점
멀티 스레드에 특화된 방식이 아니다.
Async / Sync, Blocking / Non-blocking ?
운영체제가 내부적으로 비동기 IO 작업을 한 뒤 IO 작업이 끝나면 그 걸 알려주는 방식으로 동작
하기 때문에 Asynchronous 방식이다.
또 I/O 작업이 완료되지 않아도 함수는 바로 리턴되고 다음 명령어로 넘어가 다른 작업을 수행
할 수 있기 때문에 non-blocking 방식이다.
Bonus
Coroutine
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Routine A Coroutine Routine B
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
Routine A
작업 진행
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
이 시점에서
Coroutine
호출하여
Coroutine의
일부 수행
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
다시 원래 함
수 호출하여
진행하던 부
분부터 다음
부분 진행
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
이 때 다른 루
틴 B에서 자기
작업 수행
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
이 시점에서
Coroutine
호출. 이전 호
출 지점에서
부터 이어서
진행됨.
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
다시 원래 함
수 호출해서
하던 작업 끝
까지 마무리
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
이 때 루틴
A에서 다시
Coroutine
호출하면 이
전 부분부터
이어서 진행
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
Coroutine Routine BRoutine A
다시
루틴 A
호출하여
나머지 수행
Bonus Coroutine
•	Coroutine
함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출
할 수 있는 것.
이러한 특성 덕분에 비동기적인 로직 처리에 굉장히 유용하게 사용될 수 있다. AI의 FSM 구현
등을 쉽게 만드는 것 등에도 이용할 수 있다고 함.
C++에서의 사용
C++ 언어에서 정식으로 지원하지는 않고(MS에서 C++ 17 표준에 __resumable / __await
라는 코루틴 관련 기능을 제출했다고는 함) boost 라이브러리를 이용하면 코루틴을 이용할 수
있긴 하다.
Bonus Coroutine
•	Coroutine
예제 코드
template<typename T>
using coro_t = boost::coroutines::coroutine<T>;
void test(coro_t<void ()>::caller_type& caller)
{
	 printf(“first testn”);
	caller();
	 printf(“second testn”);
	caller();
}
int main()
{
	 printf(“first mainn”);
	 coro_t<void ()> coro(test);
	 printf(“second mainn”);
	coro();
	if(!coro)
	{
		printf(“exitn”);
	}
	 return 0;
}
실행 결과
first main
first test
second main
second test
exit
End
Thank You!
End Thank You!
•	참고 자료
•	 TCP State 관련
http://kuaaan.tistory.com/118
http://en.wikipedia.org/wiki/Nagle’s_algorithm
•	 IO Multiplexing, Sync / Async IO 관련
http://www.terabit.com.au/docs/Comparison.htm
http://icourse.cuc.edu.cn/networkprogramming/lectures/
Unit9_WinSock_Multiplex.pdf
•	 Coroutine 관련
http://www.gamedevforever.com/200
http://gamedevforever.com/209
http://www.gamedevforever.com/289

Weitere ähnliche Inhalte

Was ist angesagt?

[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅DongMin Choi
 
실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략YEONG-CHEON YOU
 
Ndc14 분산 서버 구축의 ABC
Ndc14 분산 서버 구축의 ABCNdc14 분산 서버 구축의 ABC
Ndc14 분산 서버 구축의 ABCHo Gyu Lee
 
게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP Adv게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP AdvSeungmo Koo
 
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기강 민우
 
LockFree Algorithm
LockFree AlgorithmLockFree Algorithm
LockFree AlgorithmMerry Merry
 
NDC12_Lockless게임서버설계와구현
NDC12_Lockless게임서버설계와구현NDC12_Lockless게임서버설계와구현
NDC12_Lockless게임서버설계와구현noerror
 
빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)YEONG-CHEON YOU
 
Multiplayer Game Sync Techniques through CAP theorem
Multiplayer Game Sync Techniques through CAP theoremMultiplayer Game Sync Techniques through CAP theorem
Multiplayer Game Sync Techniques through CAP theoremSeungmo Koo
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개MinGeun Park
 
이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015
이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015
이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015devCAT Studio, NEXON
 
게임서버프로그래밍 #8 - 성능 평가
게임서버프로그래밍 #8 - 성능 평가게임서버프로그래밍 #8 - 성능 평가
게임서버프로그래밍 #8 - 성능 평가Seungmo Koo
 
게임프로젝트에 적용하는 GPGPU
게임프로젝트에 적용하는 GPGPU게임프로젝트에 적용하는 GPGPU
게임프로젝트에 적용하는 GPGPUYEONG-CHEON YOU
 
Multithread & shared_ptr
Multithread & shared_ptrMultithread & shared_ptr
Multithread & shared_ptr내훈 정
 
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화sung ki choi
 
RPC에서 REST까지 간단한 개념소개
RPC에서 REST까지 간단한 개념소개RPC에서 REST까지 간단한 개념소개
RPC에서 REST까지 간단한 개념소개Wonchang Song
 
임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012devCAT Studio, NEXON
 
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지강 민우
 
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019devCAT Studio, NEXON
 
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리YEONG-CHEON YOU
 

Was ist angesagt? (20)

[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
 
실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략
 
Ndc14 분산 서버 구축의 ABC
Ndc14 분산 서버 구축의 ABCNdc14 분산 서버 구축의 ABC
Ndc14 분산 서버 구축의 ABC
 
게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP Adv게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP Adv
 
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
 
LockFree Algorithm
LockFree AlgorithmLockFree Algorithm
LockFree Algorithm
 
NDC12_Lockless게임서버설계와구현
NDC12_Lockless게임서버설계와구현NDC12_Lockless게임서버설계와구현
NDC12_Lockless게임서버설계와구현
 
빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)
 
Multiplayer Game Sync Techniques through CAP theorem
Multiplayer Game Sync Techniques through CAP theoremMultiplayer Game Sync Techniques through CAP theorem
Multiplayer Game Sync Techniques through CAP theorem
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개
 
이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015
이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015
이승재, 마비노기 듀얼: 분산 데이터베이스 트랜잭션 설계와 구현, NDC2015
 
게임서버프로그래밍 #8 - 성능 평가
게임서버프로그래밍 #8 - 성능 평가게임서버프로그래밍 #8 - 성능 평가
게임서버프로그래밍 #8 - 성능 평가
 
게임프로젝트에 적용하는 GPGPU
게임프로젝트에 적용하는 GPGPU게임프로젝트에 적용하는 GPGPU
게임프로젝트에 적용하는 GPGPU
 
Multithread & shared_ptr
Multithread & shared_ptrMultithread & shared_ptr
Multithread & shared_ptr
 
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
 
RPC에서 REST까지 간단한 개념소개
RPC에서 REST까지 간단한 개념소개RPC에서 REST까지 간단한 개념소개
RPC에서 REST까지 간단한 개념소개
 
임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012
 
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
 
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
 
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
 

Ähnlich wie Tcp ip & io model

Concurrent servers
Concurrent serversConcurrent servers
Concurrent serversTonyYoon12
 
네트워크 프로그래밍 입출력 다중화 & 논블록소켓
네트워크 프로그래밍 입출력 다중화 & 논블록소켓네트워크 프로그래밍 입출력 다중화 & 논블록소켓
네트워크 프로그래밍 입출력 다중화 & 논블록소켓Eutark Park
 
Python으로 채팅 구현하기
Python으로 채팅 구현하기Python으로 채팅 구현하기
Python으로 채팅 구현하기Tae Young Lee
 
소켓프로그래밍 기초요약
소켓프로그래밍 기초요약소켓프로그래밍 기초요약
소켓프로그래밍 기초요약세빈 정
 
Zoo keeper 소개
Zoo keeper 소개Zoo keeper 소개
Zoo keeper 소개주표 홍
 
하드웨어 스타트업의 소프트웨어 이야기
하드웨어 스타트업의 소프트웨어 이야기하드웨어 스타트업의 소프트웨어 이야기
하드웨어 스타트업의 소프트웨어 이야기Mijeong Park
 
More effective c++ 2
More effective c++ 2More effective c++ 2
More effective c++ 2현찬 양
 
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?nexusz99
 
Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015Kris Jeong
 
[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성NAVER D2
 
고급시스템프로그래밍
고급시스템프로그래밍고급시스템프로그래밍
고급시스템프로그래밍kimkiweon
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례SangIn Choung
 
TCP/IP Protocol - JAVA
TCP/IP Protocol - JAVATCP/IP Protocol - JAVA
TCP/IP Protocol - JAVAcooddy
 
Asynchronous agents library(aal)pdf
Asynchronous agents library(aal)pdfAsynchronous agents library(aal)pdf
Asynchronous agents library(aal)pdfHYUNWOO KIM
 
Kubernetes in action
Kubernetes in actionKubernetes in action
Kubernetes in actionBingu Shim
 
Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQLI Goo Lee
 
[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술NAVER D2
 
Implementing remote procedure calls rev2
Implementing remote procedure calls rev2Implementing remote procedure calls rev2
Implementing remote procedure calls rev2Sung-jae Park
 
[E6]2012. netty internals
[E6]2012. netty internals[E6]2012. netty internals
[E6]2012. netty internalsNAVER D2
 
Network programming report
Network programming reportNetwork programming report
Network programming reportJongwon
 

Ähnlich wie Tcp ip & io model (20)

Concurrent servers
Concurrent serversConcurrent servers
Concurrent servers
 
네트워크 프로그래밍 입출력 다중화 & 논블록소켓
네트워크 프로그래밍 입출력 다중화 & 논블록소켓네트워크 프로그래밍 입출력 다중화 & 논블록소켓
네트워크 프로그래밍 입출력 다중화 & 논블록소켓
 
Python으로 채팅 구현하기
Python으로 채팅 구현하기Python으로 채팅 구현하기
Python으로 채팅 구현하기
 
소켓프로그래밍 기초요약
소켓프로그래밍 기초요약소켓프로그래밍 기초요약
소켓프로그래밍 기초요약
 
Zoo keeper 소개
Zoo keeper 소개Zoo keeper 소개
Zoo keeper 소개
 
하드웨어 스타트업의 소프트웨어 이야기
하드웨어 스타트업의 소프트웨어 이야기하드웨어 스타트업의 소프트웨어 이야기
하드웨어 스타트업의 소프트웨어 이야기
 
More effective c++ 2
More effective c++ 2More effective c++ 2
More effective c++ 2
 
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
Dropbox와 같은 시스템은 파일을 어떻게 저장할까?
 
Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015
 
[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성
 
고급시스템프로그래밍
고급시스템프로그래밍고급시스템프로그래밍
고급시스템프로그래밍
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례
 
TCP/IP Protocol - JAVA
TCP/IP Protocol - JAVATCP/IP Protocol - JAVA
TCP/IP Protocol - JAVA
 
Asynchronous agents library(aal)pdf
Asynchronous agents library(aal)pdfAsynchronous agents library(aal)pdf
Asynchronous agents library(aal)pdf
 
Kubernetes in action
Kubernetes in actionKubernetes in action
Kubernetes in action
 
Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQL
 
[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술
 
Implementing remote procedure calls rev2
Implementing remote procedure calls rev2Implementing remote procedure calls rev2
Implementing remote procedure calls rev2
 
[E6]2012. netty internals
[E6]2012. netty internals[E6]2012. netty internals
[E6]2012. netty internals
 
Network programming report
Network programming reportNetwork programming report
Network programming report
 

Mehr von Nam Hyeonuk

Next 게임 실전 프로젝트 슬라이드
Next 게임 실전 프로젝트 슬라이드Next 게임 실전 프로젝트 슬라이드
Next 게임 실전 프로젝트 슬라이드Nam Hyeonuk
 
Haskell study 15
Haskell study 15Haskell study 15
Haskell study 15Nam Hyeonuk
 
Haskell study 14
Haskell study 14Haskell study 14
Haskell study 14Nam Hyeonuk
 
Haskell study 13
Haskell study 13Haskell study 13
Haskell study 13Nam Hyeonuk
 
Haskell study 12
Haskell study 12Haskell study 12
Haskell study 12Nam Hyeonuk
 
Haskell study 11
Haskell study 11Haskell study 11
Haskell study 11Nam Hyeonuk
 
Haskell study 10
Haskell study 10Haskell study 10
Haskell study 10Nam Hyeonuk
 
Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object poolingNam Hyeonuk
 

Mehr von Nam Hyeonuk (20)

Next 게임 실전 프로젝트 슬라이드
Next 게임 실전 프로젝트 슬라이드Next 게임 실전 프로젝트 슬라이드
Next 게임 실전 프로젝트 슬라이드
 
Haskell study 15
Haskell study 15Haskell study 15
Haskell study 15
 
Haskell study 14
Haskell study 14Haskell study 14
Haskell study 14
 
Haskell study 13
Haskell study 13Haskell study 13
Haskell study 13
 
Haskell study 12
Haskell study 12Haskell study 12
Haskell study 12
 
Haskell study 11
Haskell study 11Haskell study 11
Haskell study 11
 
Haskell study 10
Haskell study 10Haskell study 10
Haskell study 10
 
Haskell study 9
Haskell study 9Haskell study 9
Haskell study 9
 
Haskell study 8
Haskell study 8Haskell study 8
Haskell study 8
 
Haskell study 7
Haskell study 7Haskell study 7
Haskell study 7
 
Haskell study 6
Haskell study 6Haskell study 6
Haskell study 6
 
Haskell study 5
Haskell study 5Haskell study 5
Haskell study 5
 
Haskell study 4
Haskell study 4Haskell study 4
Haskell study 4
 
Haskell study 3
Haskell study 3Haskell study 3
Haskell study 3
 
Haskell study 2
Haskell study 2Haskell study 2
Haskell study 2
 
Haskell study 1
Haskell study 1Haskell study 1
Haskell study 1
 
Haskell study 0
Haskell study 0Haskell study 0
Haskell study 0
 
Multi thread
Multi threadMulti thread
Multi thread
 
Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object pooling
 
Database
DatabaseDatabase
Database
 

Tcp ip & io model

  • 2. 01 nagle algorithm “가능하면 조금씩 여러 번 보내지 말고 한 번에 많이 보내라”
  • 3. 01 nagle algorithm • 왜 필요한가? 패킷은 보낼 때마다 고정적인 비용(packet header)이 필요하다. 작은 크기의 패킷을 여러 번 보낼 경우 이 고정 비용때문에 네트워크 자원을 그만큼 더 많이 쓰게 된다. 이걸 버퍼에 모아두었 다가 되도록 묶어서 한 번에 보냄으로써 네트워크 자원을 효율적으로 쓰는 것이다. • 게임에서는? Nagle 알고리즘을 쓰면 네트워크 자원을 효율적으로 쓸 수 있긴 하지만 반대로 응답 속도가 안 좋아지게 된다. 그 때 그 때 보내는 게 아니라 모아서 보내기 때문. 따라서 반응 속도가 중요한 게 임의 경우 Nagle 알고리즘을 쓰지 않는게 좋을 때도 많다. 물론 항상 그렇듯이 case by case이기 때문에, 항상 Nagle을 쓰는게 좋고 항상 Nagle을 안 쓰 는게 좋고 이렇게 이야기할 수는 없다. 자신이 처한 상황에 따라 쓸 지 안 쓸 지 적절히 선택하는 게 좋다.
  • 4. 01 nagle algorithm • 동작 원리 Host A Host B Host A Host B Nagle OFF Nagle ON ACK ACK ACK ACK ACK N A G L E N ACK ACK AGLE
  • 5. 01 nagle algorithm • C++에서의 구현 int opt = true; setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(int)); Nagle 알고리즘은 기본적으로 ON되어 있다. 그래서 Nagle 알고리즘을 쓰지 않고 싶을 경우 위 코드를 이용해 Nagle 알고리즘의 사용을 해제할 수 있다. - setsockopt : 소켓의 옵션을 변경하기 위해 사용되는 함수다. 인자로 소켓 / 소켓의 레벨 / 지정할 옵션 / 옵션 값을 지정하기 위한 포인터 / 옵션 값의 크기 를 받는다. - IPPROTO_TCP : soket의 레벨 값으로는 IPPROTO_TCP와 SOL_SOCKET 두 가지가 있 다. 어떤 레벨이냐에 따라 지정가능한 옵션이 다른데 IPPROTO_TCP로 해야 Nagle 알고리즘 사 용여부 옵션을 바꿀 수 있다. - TCP_NODELAY : 이름에서도 알 수 있듯이 이 옵션 값을 1로 하면(적용시켜주면) Nagle 알 고리즘이 꺼진다.
  • 6. 02 TCP States “단절을 감지하고, 우아하게 연결을 끊는 방법은?”
  • 7. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED
  • 8. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN
  • 9. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN 3way- handshaking 과정을 통한 서버-클라이언트 연결 시작
  • 10. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN SYN RECEIVED SYN/SYN+ACK
  • 11. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN SYN RECEIVED SYN/SYN+ACK ESTABLISHED SYN+ACK/SYN 클라이언트 성공적으로 연결 완료!
  • 12. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN SYN RECEIVED SYN/SYN+ACK ESTABLISHED SYN+ACK/SYN ESTABLISHED ACK 서버도 성공적으로 연결 완료!
  • 13. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN SYN RECEIVED SYN/SYN+ACK ESTABLISHED SYN+ACK/SYN ESTABLISHED ACK 이제 서로 데이터를 주고 받는다.
  • 14. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN SYN RECEIVED SYN/SYN+ACK ESTABLISHED SYN+ACK/SYN ESTABLISHED ACK 이 때 데이터를 주고 받다 가 한 쪽에서 연결이 끊어 지면? 비정상적인 연결 끊김!
  • 15. 02 TCP States • 유령 세션은 왜 생기나? Server Client CLOSED CLOSED LISTEN LISTEN SYN SENT CONNECT/SYN SYN RECEIVED SYN/SYN+ACK ESTABLISHED SYN+ACK/SYN ESTABLISHED ACK 정상적 종료가 아니면 왜 데이터가 안 오는 지 알 수 없으므로 올 때까지 기 다린다! WAIT...
  • 16. 02 TCP States • 유령 세션은 왜 생기나? 아까 전 그림처럼 정상적으로 ‘연결이 종료되었음’이라는 메시지 없이 연결이 비정상적으로 끊 겼을 경우 무한히 대기하게 된다. 어떤 네트워크 사정때문에 데이터의 전송이 늦어지는 건지 아 니면 연결에 문제가 있는 건지 알 수 없기 때문이다. 이 때문에 유령 세션이 발생하게 된다. • 해결 방법 TCP 특성 상 깔끔하게 해결하기는 쉽지 않다. heartbeat : 심장 박동처럼 일정 주기로 서버와 클라이언트가 패킷을 주고 받으면서 서로 살아 있는지 검사하는 방법이다. keepalive : 소켓에서 자체적으로 heartbeat처럼 검사하는 방법이다. 일정 시간을 설정한 다음 그 시간을 넘으면 검사 패킷을 보내고 일정 이상 응답이 오지 않으면 연결을 종료시킨다.
  • 17. 02 TCP States • TCP_LINGER 옵션 소켓의 연결을 종료할 때 미처 전송되지 못하고 버퍼에 남아있는 데이터를 어떻게 처리할 것인지 결정하기 위한 옵션이다. l_onoff와 l_linger 두 가지 옵션이 있다. l_onoff는 linger 옵션을 사 용할 건지 말 건지를 결정한다. 기본적으로는 linger 옵션 사용 안하고, close 호출 시 내부적으 로 정상적인 종료 과정을 진행한다. l_onoff = 1, l_linger = 0 closesocket() 즉시 리턴. 버퍼에 남아 있는 데이터는 모두 파기한다. l_onoff = 1, l_linger > 0 일단 정상적인 종료 과정(Graceful Shutdown)을 진행하되, 지정한 시간(l_linger)이 지나도 제대로 완료되지 않으면 무시하고 위와 마찬가지로 즉시 연결 종료 후 남은 데이터는 파기시킨 다.
  • 18. 02 TCP States • TCP_LINGER 옵션 사용법 코드 예제 //Linger 옵션 지정용 구조체 LINGER ling = {0, }; ling.l_onoff = 1; //LINGER 옵션 사용 ling.l_linger = 0; //몇 초 기다릴 지 시간 설정 //LINGER 옵션 특정 소켓에 적용. setsockopt(socket, SOL_SOCKET, SO_LINGER, (CHAR*)&ling, sizeof(ling)); // 해당 옵션이 적용된 socket 종료 과정 수행. closesocket(socket);
  • 19. 02 TCP States • Graceful Shutdown 데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정. ServerClient ESTABLISHED ESTABLISHED
  • 20. 02 TCP States • Graceful Shutdown 데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정. ServerClient ESTABLISHED ESTABLISHED FIN FIN_WAIT_1 CLOSE_WAIT연결 종료를 시작한다는 의미로 Client에서 FIN을 보낸다.
  • 21. 02 TCP States • Graceful Shutdown 데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정. ServerClient ESTABLISHED ESTABLISHED FIN FIN_WAIT_1 CLOSE_WAIT ACK FIN_WAIT_2 Server는 그에 대한 응답 을 보내고 연결을 종료하 기 위한 준비를 한다.
  • 22. 02 TCP States • Graceful Shutdown 데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정. ServerClient ESTABLISHED ESTABLISHED FIN FIN_WAIT_1 CLOSE_WAIT ACK FIN_WAIT_2 LAST_ACK FIN TIME_WAIT 준비가 끝나면 client에 FIN을 보내 연결을 종료 할 것임을 알린다.
  • 23. 02 TCP States • Graceful Shutdown 데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정. ServerClient ESTABLISHED ESTABLISHED FIN FIN_WAIT_1 CLOSE_WAIT ACK FIN_WAIT_2 LAST_ACK FIN TIME_WAIT CLOSED FIN을 받아도 Client는 종료되지 않고 한동안 TIME_WAIT가 된다. 네트워크 문제로 FIN보 다 늦게 도착하는 패킷이 존재할 수 있기 때문. ACK
  • 24. 02 TCP States • Graceful Shutdown 데이터의 유실 없이 안전하게 소켓 간의 연결을 종료하기 위한 과정. ServerClient ESTABLISHED ESTABLISHED FIN FIN_WAIT_1 CLOSE_WAIT ACK FIN_WAIT_2 LAST_ACK FIN TIME_WAIT CLOSED ACK CLOSED 이렇게 일정 시간이 지나면 종료시킴.
  • 25. 02 TCP States • Graceful Shutdown Graceful Shutdown에서 주의해야할 점은 다음과 같다. 1. TIME_WAIT는 먼저 종료를 시작한 쪽에서 생긴다. Graceful Shutdown과정에서 TIME_WAIT가 생기는 건 불가피한 일이다. 하지만 TIME_ WAIT단계가 서버에서 발생한다면 서버 부하의 원인이 될 수 있으므로 꼭 클라이언트에서 종료 를 시작하게 만들자. 2. Server에서 TIME_WAIT가 안 생기게 하는 법 • 서버에서 클라이언트에 종료하라는 커맨드를 보낸다 • 수신한 클라이언트는 종료하겠다 전송 후 closesocket() 수행 • 클라이언트의 종료하겠다는 메시지 받은 서버는 해당 소켓에 대해 closesocket() 호출. 이 때 linger 옵션을 이용해 혹시 모를 TIME_OUT을 막음(어차피 서버에서 클라이언트로 보낼 데이터는 없을게 확실하기 때문에 linger 옵션을 사용)
  • 26. 03 IO Model “다양한 네트워크 IO 모델의 장단점을 알아보자”
  • 27. 03 IO Model • Synchronous Vs Asynchronous Synchronous(동기) 작업을 요청한 후 해당 작업의 결과가 나올 때까지 기다린 후 처리하는 것 . IO 작업에 대한 readiness를 기다린다. 특정 IO 작업을 하기 위한 준비가 되었는 지에 집중. 그 런 이벤트의 발생을 기다렸다가 그 이벤트가 발생하면 그에 따른 적합한 처리를 한다. Asynchronous(비동기) 작업을 요청해놓고 딴 일을 하다가 해당 작업이 완료되면 그 때 완료되었음을 통지 받고 그에 따 른 처리를 하는 것이다. IO 작업의 completion을 기다린다. 운영체제 단계의 비동기 API를 통해 이루어지며 IO 작업이 completion되면 그에 적합한 Handler를 이용해 처리를 한다.
  • 28. 03 IO Model • Blocking Vs Non-blocking I/O 작업에서 Blocking으로 동작할 경우 해당 I/O가 끝날 때까지 대기해야하고(I/O가 끝나기 전에는 함수가 반환되지 않는다), Non-Blocking으로 동작할 경우 작업을 완료할 수 있다면 완 료하고 그렇지 못한 상황이라면 대기하지 않고 리턴해버린다. Socket에서의 Non-Blocking 설정 ULONG isNonblocking = 1; ioctlsocket(socket, FIONBIO, &isNonBlocking); ioctlsocket : 특정 socket의 I/O 상태를 바꿀 때 사용하는 함수다. FIONBIO : 3번째 인자로 넘어온 속성 값이 0이면 Blocking, 0이 아니면 non-blocking으로 설정한다. &isNonBlocking : 속성 값을 지정한 변수의 주소를 넘긴다.
  • 29. 03 IO Model • Blocking Vs Non-blocking Non-Blocking Socket의 IO non-blocking socket에서 데이터를 전부 받으려면 아래처럼 해야한다 for (;;) { if (recvLen = recv(socket, str + length, strLen, 0) < 0) { if (WSAGetLastError() == WSAEWOULDBLOCK) Sleep(1000); // 기다림 } else { length += recvLen; if (length >= strLen) break; } } recvLen은 이번에 받은 양, strLen은 받고자 하는 길이, length는 받은 양의 누적 합이다. non-blocking은 recv를 호출해도 바로 리턴되기 때문에 데이터를 끝까지 읽지 못했거나 하나 도 못 읽은 경우가 발생할 수 있다. 따라서 recv 호출 후에 얼만큼 읽었는지, 현재 socket의 상태 가 어떤 지 확인하고 그에 따른 처리를 해 줘야 한다.
  • 30. 03 IO Model • IO 이벤트 통지 모델 구세대 네트워크 I/O 방식 Server Thread1 Thread2 Thread3 Thread4 Client1 Client2 Client3 Client4 접속한 각각의 클라이언 트 별로 Thread를 하나씩 두고 따로 처리하게 만든 다. 이용자 수가 많을 수록 Thread간의 컨텍스트 스 위칭 비용이 커진다. I/O 이벤트 통지 모델이 필요한 이유 이벤트 통지 모델을 이용하면 Thread 개수를 훨씬 줄일 수 있다. 동시 접속자 수가 많을 수록 이 벤트 통지 모델을 이용하는 편이 성능이 좋을 것이다.
  • 31. 03 IO Model • SELECT SELECT는 이벤트 별로 감시할 소켓들을 등록하고(fd_set), 등록된 소켓에 뭔가 이벤트가 발생 했을 경우 그걸 확인하는 방식으로 동작한다. int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout); 첫 번째 인자로 검사할 fd(file descriptor)의 개수를 설정한다. 0~fd-1까지를 검사한다. readfds, writefds, errorfds는 각각의 이벤트에 대해 검사할 소켓의 목록을 저장한 비트필드 의 포인터이다(nullptr이면 해당 이벤트는 체크 안함). fd_set을 만들기 위해 다음과 같은 함수 들을 이용한다. void FD_ZERO(fd_set* fdset) : 해당 fd_set의 값을 모두 0으로 초기화한다. void FD_CLR(int fd, fd_set* fdset) : 해당 fd_set에서 fd에 해당하는 비트를 0으로 만든다. void FD_SET(int fd, fd_set* fdset) : 해당 fd_set에서 fd에 해당하는 비트를 1로 만든다. void FD_ISSET(int fd, fd_set* fdset) : fd_set에서 fd에 해당하는 비트가 1인지 검사한다.
  • 32. 03 IO Model • SELECT 예제 코드 FD_ZERO(&readsets); while (true) { FD_SET(socket, &readsets); n = select(max_fd + 1, &readsets, nullptr, nullptr, nullptr); if (n < 0) //error 처리 return -1; for (int i = 0; i < max_fd; i++) { if (FD_ISSET(i, &readsets)) { // ... recv, accept 등 처리 } } }
  • 33. 03 IO Model • SELECT 장점 지원하는 OS가 많아 이식성이 좋다(POSIX 표준). 단점 검사할 수 있는 fd 개수에 제한이 있다(최대 1024개). 매번 검사할 때마다 루프로 전체 fd를 다 검사해야하기 때문에 속도가 느리다. Async / Sync, Blocking / Non-blocking ? OS 레벨에서 비동기로 IO 작업을 하며 IO가 끝났음을 통지 받아서 처리하는 것이 아니라 자 체적인 event loop를 통해 매번 소켓의 상태가 변했는지 확인한 뒤 그에 따른 처리를 하므로 Synchronous. timeout을 nullptr로 설정하면 뭔가 이벤트가 발생할 때까지 진행하지 않는다. 따라서 이 경우 는 Blocking이다. timeout를 설정할 경우 해당 시간이 지나면 아무 이벤트가 발생하지 않아도 넘어가므로 Non-blocking이 된다.
  • 34. 03 IO Model • EPOLL select의 단점을 개선한 것이다. select가 매번 모든 fd를 다 검사해야하는 반면 epoll은 검사할 fd만 등록해 놓으면 커널이 그 fd들을 관리하면서 이벤트 발생 여부를 알려주기 때문에 더 효율 이 뛰어나다. epoll_create(int size) epoll을 위한 인스턴스를 생성한 뒤 그 fd를 돌려준다. epoll_ctl(int epfd, int op, int fd, struct epoll_event* event) epoll에 이벤트 등록 등의 일을 담당하는 함수다. epfd: epoll_create로 받은 epoll 인스턴스 의 fd. op : 어떤 동작을 할 지 결정. EPOLL_CTL_ADD는 epoll 인스턴스에 감시할 fd 추가, EPOLL_CTL_MOD는 등록된 fd와 연관된 event 변경, EPOLL_CTL_DEL은 등록된 fd의 삭 제. 마지막 인자는 어떤 이벤트를 통지 받을 지 구조체를 정해 넘긴다. epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout) epoll_create로 만든 인스턴스의 번호를 넘기면 이벤트가 발생할 때까지 지정한 시간 만큼 기 다렸다가 이벤트가 발생한 fd들을 반환한다.
  • 35. 03 IO Model • EPOLL 예제 코드 epollfd = epoll_create(10); //epoll 인스턴스 생성 if (epollfd == -1) return -1; ev.envents = EPOLLIN; //읽을 수 있는 지(accept) ev.data.fd = listenSock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenSock, &ev) == -1) return -1; while (true){ if ((nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1)) == -1) return -1; for (n = 0; n < nfds; ++n){ if (events[n].data.fd == listenSock){ connSock = accept(listen_sock, (struct sockaddr *) &local, &addrlen); if (connSock == -1) return -1; setnonblocking(connSock); // 논블로킹 설정 ev.events = EPOLLIN | EPOLLET; ev.data.fd = connSock; //accept된 socket도 epoll에 추가(recv 이벤트 통지). if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connSock, &ev) == -1) return -1; } else do_use_fd(events[n].data.fd); //읽은 데이터 처리 } }
  • 36. 03 IO Model • EPOLL 장점 select와는 다르게 관리할 수 있는 fd 개수의 제한이 없다. 관리할 fd를 한 번만 등록하면 커널에서 관리하며 이벤트가 발생한 것만 넘겨주므로 루프 돌 때 마다 매 번 검사해야하는 select보다 훨씬 효율적이다. 단점 리눅스 커널 2.6 이상에서만 지원하므로 이식성이 떨어진다. Async / Sync, Blocking / Non-blocking ? Select와 마찬가지 이유로 Synchronous. Select와 마찬가지로 timeout을 nullptr로 설정하면 뭔가 이벤트가 발생할 때까지 진행하지 않는다. 따라서 이 경우는 Blocking이고, timeout를 설정할 경우 Non-Blocking이 된다.
  • 37. 03 IO Model • WSAAsyncSelect 특정 소켓에 대해 통지 받을 이벤트와 통지 받을 때 사용할 메시지를 지정해주면 해당 이벤트가 생길 때 메시지 큐를 이용해 윈도우 메시지의 형태로 통지해주는 방식이다. WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent) s : 이벤트를 통지받을 소켓. hWnd : 메시지를 보낼 윈도우의 핸들. wMsg : 해당 이벤트를 통지할 때 사용할 윈도우 메시지 값이다. lEvent : 통지 받을 이벤트. 주로 사용되는 값으로 FD_ACCEPT, FD_READ, FD_WRITE, FD_CONNECT, FD_CLOSE등이 있다.
  • 38. 03 IO Model • WSAAsyncSelect 예제 코드 int main() { ... WSAAsyncSelect(socket, hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE); ... } LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch(wMsg) { case WM_SOCKET: switch(WSAGETSELECTEVENT(lParam)) { case FD_READ: ... break; case FD_WRITE: ... break; } break; } }
  • 39. 03 IO Model • WSAAsyncSelect 장점 소켓 이벤트를 윈도우 메시지 형태로 전달 받을 수 있다. 다른 메시지 처리하듯이 일관성 있게 처 리 가능하므로 편리하다. 단점 윈도우 메시지 큐 기반이므로 사용하지 않더라도 윈도우를 반드시 띄워야 한다. 하나의 윈도우에서 윈도우 메시지와 소켓 메시지를 동시에 처리해야하므로 성능이 저하될 수 있 다. Async / Sync, Blocking / Non-blocking ? 특정 IO 작업이 완료되면 운영체제가 그때 그때 메시지를 보내주기 때문에 Asyncronous이다. WSAAsyncSelect 함수를 호출하면 해당 socket이 자동으로 non-blocking으로 바뀐다. 따 라서 이 socket에 대한 IO 작업도 non-blocking으로 이루어지므로 non-blocking이다.
  • 40. 03 IO Model • WSAEventSelect WSAAsyncSelect가 메시지 형태로 처리하는 것과는 다르게 특정 네트워크 이벤트가 발생했을 때 이와 연동시킬 이벤트 오브젝트를 등록하는 방식으로 처리된다. WSAEVENT WSACreateEvent() 이벤트 객체를 생성해서 돌려준다. int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents) 소켓과 이벤트 객체를 짝짓는다. s는 이벤트를 감지할 소켓, hEventObject는 해당 결과를 통지 받기 위한 이벤트 객체의 핸들, lNetworkEvents는 감지할 이벤트의 종류다. WSAAsyncSelect와 동일하게 FD_READ, FD_WRITE, FD_ACCEPT, FD_CLOSE 등등의 값 을 이용한다. DWORD WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT * lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable) 이벤트가 발생할 때까지 기다린다.이벤트 개수, 이벤트들의 배열, 전체 이벤트 배열의 signal이 바뀔 때까지 기다릴지 여부, 타임 아웃 시간, alertable state 설정 여부 등을 지정한다.
  • 41. 03 IO Model • WSAEventSelect 예제 코드 //event 생성 및 설정 eventArray[0] = WSACreateEvent(); ... WSAEventSelect(sockets[0], eventArray[0], FD_READ | FD_CLOSE); while(true) { index = WSAWaitForMultipleEvents(totalEvent, eventArray, false, WSA_INFINITE, false); index = index - WSA_WAIT_EVENT_0; WSAEnumNetworkEvents(sockets[index], eventArray[index], &netEvents); //각 이벤트에 맞는 처리. if(netEvents.lNetworkEvents & FD_READ) { ... } if(netEvents.lNetworkEvents & FD_CLOSE) { ... } }
  • 42. 03 IO Model • WSAEventSelect 장점 무조건 윈도우를 만들어줘야 하는 WSAAsyncSelect와는 다르게 윈도우를 만들어 주지 않아 도 사용 가능하다. 단점 WaitForMultipleObject에서 처리가능한 최대 이벤트 개수가 64개다. 그 이상 처리를 위해서 는 스레드를 늘려야한다. WaitForMultipleObject가 한 번에 여러 개 이벤트가 왔을 경우 배열에서 가장 앞 인덱스를 돌 려준다. 이것만 처리하면 뒤쪽 이벤트는 잘 처리가 안 될 수 있으므로 배열의 다른 인덱스들도 확 인을 해 주어야 한다. Async / Sync, Blocking / Non-blocking ? Select와 비슷하게 폴링하는 방식이므로 Synchronous이다. WSAEventSelect도 WSAAsyncSelect와 마찬가지로 소켓을 자동으로 non-blocking으로 바꾼다. 따라서 non-blocking이다.
  • 43. 03 IO Model • Overlapped I/O Callback WSASend, WSARecv를 할 때 Overlapped 구조체 설정을 통해 I/O를 중첩시킬 수 있다. 완 료 루틴 함수까지 인자로 넘겨주면 해당 I/O 작업이 끝나고 난 뒤 완료 루틴 함수를 호출해준다. WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) 여기서 처음 5개 인자는 일반적인 recv/ send 함수와 별반 다를 바 없다. 중요한 건 lpOverlapped 인자와 lpCompletionRoutine 인자이다. lpOverlapped 인자로 WSAOVERLAPPED 구조체의 주소값을 넘기는데, 이 구조체에 I/O 작업이 끝났음을 통지하기 위한 이벤트를 등록해서 넘긴다. lpCompletionRoutine 인자로는 I/O 작업이 끝났을 때 수행 할 함수의 주소를 넘긴다. 그러면 I/O 작업이 끝난 다음 APC 큐에 들어가서 하나씩 완료 루틴 함 수를 수행하게 된다.
  • 44. 03 IO Model • Overlapped I/O Callback 예제 코드 //완료 루틴 함수 void WINAPI IOCompletionRoutine(DWORD dwError, DWORD cbTransferred, LPOVERLAPPED lpOverlapped, DWORD dwFlags); WSAOVERLAPPED overlapped; WSABUF dataBuf; char buffer[DATA_BUFSIZE] = { 0, }; overlapped.hEvent = WSACreateEvent(); dataBuf.len = DATA_BUFSIZE; dataBuf.buf = buffer; WSASend(socket, &dataBuf, &sendBytes, 0, &overlapped, IOCompletionRoutine); //다른 작업 수행 ... SleepEx(INFINITE, true);
  • 45. 03 IO Model • Overlapped I/O Callback 장점 사용자가 지정한 버퍼로 바로 복사가 일어나기 때문에 데이터 복사 비용이 줄어든다. 단점 멀티 스레드에 특화된 방식이 아니다. Async / Sync, Blocking / Non-blocking ? 운영체제가 내부적으로 비동기 IO 작업을 한 뒤 IO 작업이 끝나면 그 걸 알려주는 방식으로 동작 하기 때문에 Asynchronous 방식이다. 또 I/O 작업이 완료되지 않아도 함수는 바로 리턴되고 다음 명령어로 넘어가 다른 작업을 수행 할 수 있기 때문에 non-blocking 방식이다.
  • 47. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Routine A Coroutine Routine B
  • 48. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A Routine A 작업 진행
  • 49. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 이 시점에서 Coroutine 호출하여 Coroutine의 일부 수행
  • 50. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 다시 원래 함 수 호출하여 진행하던 부 분부터 다음 부분 진행
  • 51. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 이 때 다른 루 틴 B에서 자기 작업 수행
  • 52. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 이 시점에서 Coroutine 호출. 이전 호 출 지점에서 부터 이어서 진행됨.
  • 53. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 다시 원래 함 수 호출해서 하던 작업 끝 까지 마무리
  • 54. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 이 때 루틴 A에서 다시 Coroutine 호출하면 이 전 부분부터 이어서 진행
  • 55. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. Coroutine Routine BRoutine A 다시 루틴 A 호출하여 나머지 수행
  • 56. Bonus Coroutine • Coroutine 함수 내에서 호출한 쪽을 다시 호출할 수 있고, 다시 다른 routine에서 함수의 중간 지점을 호출 할 수 있는 것. 이러한 특성 덕분에 비동기적인 로직 처리에 굉장히 유용하게 사용될 수 있다. AI의 FSM 구현 등을 쉽게 만드는 것 등에도 이용할 수 있다고 함. C++에서의 사용 C++ 언어에서 정식으로 지원하지는 않고(MS에서 C++ 17 표준에 __resumable / __await 라는 코루틴 관련 기능을 제출했다고는 함) boost 라이브러리를 이용하면 코루틴을 이용할 수 있긴 하다.
  • 57. Bonus Coroutine • Coroutine 예제 코드 template<typename T> using coro_t = boost::coroutines::coroutine<T>; void test(coro_t<void ()>::caller_type& caller) { printf(“first testn”); caller(); printf(“second testn”); caller(); } int main() { printf(“first mainn”); coro_t<void ()> coro(test); printf(“second mainn”); coro(); if(!coro) { printf(“exitn”); } return 0; } 실행 결과 first main first test second main second test exit
  • 59. End Thank You! • 참고 자료 • TCP State 관련 http://kuaaan.tistory.com/118 http://en.wikipedia.org/wiki/Nagle’s_algorithm • IO Multiplexing, Sync / Async IO 관련 http://www.terabit.com.au/docs/Comparison.htm http://icourse.cuc.edu.cn/networkprogramming/lectures/ Unit9_WinSock_Multiplex.pdf • Coroutine 관련 http://www.gamedevforever.com/200 http://gamedevforever.com/209 http://www.gamedevforever.com/289