340 likes | 664 Views
Winsock2. Network 통신을 위한 프로그래밍 API Berkeley Socket 계승 (4.3BSD) Windows CE 를 제외한 모든 Platform 에서 사용가능. Socket 의 종류. 연결지향형 (Connection-oriented) TCP ( Transmission Control Protocol ) Streaming Protocol HTTP, FTP 비연결형 (Connectionless) UDP ( User Datagram Protocol )
E N D
Winsock2 • Network 통신을 위한 프로그래밍 API • Berkeley Socket 계승 (4.3BSD) • Windows CE를 제외한 모든 Platform에서 사용가능
Socket의 종류 • 연결지향형(Connection-oriented) • TCP ( Transmission Control Protocol ) • Streaming Protocol • HTTP, FTP • 비연결형(Connectionless) • UDP ( User Datagram Protocol ) • Message-based Protocol • DNS
Server흐름 Socket() 또는 WSASocket() bind() listen() accept() 또는 WSAAccept()
Client흐름 Socket() 또는 WSASocket() 주소해석 connect() 또는 WSAConnect()
Demo • BasicServer • BasicClient
Well-known Ports • Well-known Ports: 0 ~ 1023 • Registered Ports: 1024 ~ 49151 • Dynamic and/or Private Ports: 49152 ~ 65535
Well-known Ports(계속) • Win9x, WinMe • %windows% • WinNT, Win2K • %Windows%\system32\drivers\etc • IANA • http://www.iana.org/assignments/port-numbers
Socket Mode • Blocking • I/O작업이 끝날 때 까지 대기 • Non-Blocking • 함수 호출 즉시 return • WSAEWOULDBLOCK
Socket I/O Model • Blocking • select • WSAAsyncSelect • WSAEventSelect • Overlapped I/O • I/O Completion Port
Blocking • WinCE를 포함한 모든 Platform • 장점 • 구현이 쉽다. • 단점 • 많은 Thread가 필요하다.
bind listen accept ……. recv recv send send
select • WinCE를 포함한 모든 Platform • UNIX기반 Berkeley Socket에서 사용되던 모델 • 장점 • 여러 Socket처리 가능 • 단점 • 64 < FD_SETSIZE < 1024
SOCKET s; fd_set fdread; int ret; //socket생성 While(TRUE) { FD_ZERO(&fdread); FD_SET(s, &fdread); if((ret = select(0, &fdread, NULL, NULL, NULL)) == SOCK_ERROR) { // error 처리 } if(ret > 0) { if(FD_ISSET(s, &fdread)) { // socket에 read event발생 } } }
bind listen accept 64 ~ 1024 64 ~ 1024 ……. select recv/send select recv/send
WSAAsyncSelect • Win95(Winsock1)이상 • MFC CAsyncSocket • 장점 • select모델과 같은 부하 없이 많은 연결 처리 • 단점 • Window 필요
#define WM_SOCKET WM_USER + 10 #include <winsock2.h> #include <windows.h> Int WINAPI WinMain(…) { HWND hWnd; SOCKET scktListen; hWnd = CreateWindow(…); // socket생성 bind(scktListen, …); WSAAsyncSelect(scktListen, hWnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE); listen(scktListen, …); while(GetMessage(&msg, NULL, 0, 0)) { // message pump } }
BOOL CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { SOCKET scktAccept; switch(message) { case WM_PAINT: break; case WM_SOCKET: if(WSAGETSELECTERROR(lParam)) { // 에러처리 closesocket((SOCKET)wParam); break; } switch(WSAGETSELECTEVENT(lParam)) { //다음 장 참조 } } break; } return TRUE; }
switch(WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: scktAccept = accept(wParam, NULL, NULL); WSAAsyncSelect(scktAccept, hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE); break; case FD_READ: break; case FD_WRITE: break; case FD_WRITE: closesocket((SOCKET)wParam); break; } break; }
Bind WSAAsyncSelect listen Message pump accept recv send accept처리 WSAAsyncSelect send처리 . . recv처리 . .
WSAEventSelect • Win95(Winsock2)이상 • WSAEvent Object를 사용 • 장점 • Window 불필요 • 단점 • 한 Thread에서 64개의 Socket만을 처리
SOCKET scktArray[WSA_MAXIMUM_WAIT_EVENTS]; WSAEVENT evtArray[WSA_MAXIMUM_WAIT_EVENTS]; WSAEVENT evt; int nEvt = 0; // socket생성 bind(…); evt = WSACreateEvent(); WSAEventSelect(scktListen, evt, FD_ACCEPT | FD_CLOSE); listen(…); scktArray[nEvt] = scktListen; evtArray[nEvt] = evt; nEvt++; While(TREU) { iIndex = WSAWaitForMultipleEvents(nEvt, evtArray, FALSE, WSA_INFINITE, FALSE); iIndex = iIndex = WSA_WAIT_EVENT_0; if(NetworkEvents.lNetworkEvents & FD_ACCEPT) { if(0 != NetworkEvents.iErrorCode[FD_ACCEPT_BIT]) { // error 처리 break; }
scktAccept = accept(scktArray[iIndex], NULL, NULL); if(nEvt > WSA_MAXIMUM_WAIT_EVENTS) { // 최대 처리가능 갯수 closesocket(scktAccept); break; } evt = WSACreateEvent(); WSAEventSelect(scktAccept, evt, FD_READ | FD_WRITE | FD_CLOSE); evtArrary[nEvt] = evt; scktArray[nEvt] = scktAccept; nEvt++; } if(NetworkEvents.lNetworkEvents & FD_READ) { // error처리 recv(scktArray[iIndex – WSA_WAIT_EVENT_0], …); …. }
bind listen accept WSAEventSelect 64 64 ……. WSAWaitForMultipleEvents recv/send WSAWaitForMultipleEvents recv/send
Overlapped I/O • Win95(Winsock2)이상 • 장점 • 고성능 Socket I/O • 시스템이 Buffer관리 • 단점 • 한 Thread에서 64개의 Socket만을 처리
#define BUF_SIZE 4096 void main(void) { WSABUF wsaBuf; char buf[BUF_SIZE]; DWORD dwEvtCnt = 0; DWORD dwRecvBytes = 0; DWORD dwFlags = 0; WSAEVENT evtArray[WSA_MAXIMUM_WAIT_EVENTS]; WSAOVERLAPPED olAccept; SOCKET scktListen, scktAccept; // socket생성 scktAccept = accept(scktListen, NULL, NULL); evtArray[dwEvtCnt] = WSACreateEvent(); ZeroMemory(&olAccept, sizeof(WSAOVERLAPPED)); olAccept.hEvent = evtArray[dwEvtCnt]; wsaBuf.len = BUF_SIZE; wsaBuf.buf = buf; dwEvtCnt++;
if(SOCK_ERROR == WSARecv(scktAccept, &wsaBuf, 1, &dwRecvBytes, &dwFlags, &olAccept, NULL)) { if(WSA_IO_PENDING != WSAGetLastError()) { // error 처리 } } while(TRUE) { DWORD dwIndex = WSAWaitForMultipleEvents(dwEvtCnt, evtArray, FALSE, WSA_INFINITE, FALSE); WSAResetEvent(evtArray[dwIndex – WSA_WAIT_EVENT_0]); WSAGetOverlappedResult(scktAccept, &olAccept, &dwRecvBytes, FALSE, &dwFlags); if(0 == dwRecvBytes) { closesocket(scktAccept); WSACloseEvent(evtArray[dwIndex – WSA_WAIT_EVENT_0]); return; } // wsaBuf에 수신된 Data처리
dwFlags = 0; ZeroMemory(&olAccept, sizeof(WSAOVERLAPPED)); olAccept.hEvent = evtArray[dwEvtCnt]; wsaBuf.len = BUF_SIZE; wsaBuf.buf = buf; if(SOCK_ERROR == WSARecv(scktAccept, &wsaBuf, 1, &dwRecvBytes, &dwFlags, &olAccept, NULL)) { if(WSA_IO_PENDING != WSAGetLastError()) { // error 처리 } } } }
bind listen accept WSARecv 64 64 ……. WSAWaitForMultipleEvents WSAGetOverlappedResult WSARecv WSAWaitForMultipleEvents WSAGetOverlappedResult WSARecv
I/O Completion Port (IOCP) • WinNT이상 • 장점 • 우수한 성능과 확장성 제공 • 적은 수의 Thread로 많은 Socket처리 • 단점 • 초기화 복잡
Typedef struct _PER_HANDLE_DATA { SOCKET sckt; SOCKADDR_STORAGE addrClient; } PER_HANDLE_DATA, * LPPER_HANDLE_DATA hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); for(…) // 적정한 수의 WorkerThread를 생성 { CreateThread(NULL, 0, WorkerThread, hIOCP, 0, NULL); } // socket생성 scktAccept = WSAAccept(scktListen, …); // PER_HANDLE_DATA 생성 // accept된 socket을 생성된 PER_HANDLE_DATA에 할당 CreateIoCompletionPort((HANDLE)scktAccept, hIOCP, (DWORD)phd, 0); WSARecv(… );
DWORD WINAPI WorkerThrea(LPVOID lpParam) { HANDLE hIOCP = (HANDLE)lpParam; while(TRUE) { GetQueueCompletionStatus(hIOCP, …, INFINITE); // PER_HANDLE_DATA에 대한 처리 WSARecv(…); } return 0; }
CreateIoCompletionPort Create Threads bind listen WSAAccept CreateIoCompletionPort WSARecv GetQueuedCompletionStatus WSARecv GetQueuedCompletionStatus WSARecv Overlapped I/O GetQueuedCompletionStatus WSARecv NT I/O System GetQueuedCompletionStatus WSARecv
참고자료 • Network Programming for MS Windows • Windows Sockets 2.0: Write Scalable Winsock Apps Using Completion Ports • http://msdn.microsoft.com/msdnmag/issues/1000/Winsock/default.aspx
IO Completion Port + Overlapped I/O Main Thread NT I/O System CreateIoCompletePort(0,0,0,0) Worker Thread 생성 (CPU 갯수) Overlapped I/Os I/O Completion Port WSARecv FIFO Queue of Completed I/O Listen Sock 생성(lsock) WSASend CreateIoCompletePort(lsock,..) LIFO queue of blocked Work Threads Bind Listen (ls, 100) csock = Accept CreateIoCompletePort(csock,..) GetQueuedCompletionStatus Worker Thread Worker Thread