01.09

신승빈·2023년 1월 9일
0

KGCA 수업

목록 보기
91/128

Win API를 이용한 Chatting Program

Editor, Button, List 등을 쉽게 제작할 수 있음

LRESULT Sample::MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {  
	case WM_CREATE:
	{
    	// edit, button, listbox같이 Win API에서 미리 정의되어 있는 control을 통해 쉽고 빠르게 제작 가능
        // RegisterClass()를 통하 마찬가지로 User가 정의한 Control도 등록, 생성 가능
        // HMENU값을 통해 Event를 발생시킨 객체 확인
		CreateWindow(L"edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 500, 10, 200, 25, hWnd, (HMENU)1000, m_hInstance, NULL);
		CreateWindow(L"button", L"Send", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, 700, 10, 50, 25, hWnd, (HMENU)1001, m_hInstance, NULL);
		CreateWindow(L"listbox", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL, 0, 0, 500, 600, hWnd, (HMENU)1002, m_hInstance, NULL);
	}break;
	case WM_COMMAND:
	{
    	// HMENU로 등록한 객체 확인
		switch (LOWORD(wParam))
		{
			case 1001:
			{
				WCHAR szBuffer[255] = L"";
                // Control에 저장된 Text Buffer로 반환
				GetWindowText(m_hEdit, szBuffer, 255);
			}break;
		}
	}break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return  DefWindowProc(hWnd, message, wParam, lParam);
}

주의

만약 DirectX를 사용한다면 위에서 사용한 editor, button, listbox같은 기능을 모두 직접 구현해야 함(DirectX에서 화면을 초기화시키는 것 때문으로 짐작됨)
WinAPI와 socket을 함께 사용한다면 Include 순서를 지켜야 함

#include <winsock2.h>
#include <windows.h>
Reference : https://alleysark.tistory.com/63

가변인자

일반적인 가변인자의 사용법

Reference : https://woo-dev.tistory.com/53

_vsntprintf

일반적으로 가변인자는 시작할 때 인자의 개수를 매개변수로 넘기던가, 마지막 인자로 끝임을 전달해야 하는데, _vsntprintf()함수의 경우 그런 절차 없이 문자열의 format만 전달하는 방식으로 매개변수가 끝날 시점을 지정
문자열의 format이 결정되어 있다면 가변인자로 넘어올 각 매개변수의 크기와 개수가 결정되므로 상당히 흥미로운 접근법인듯

Reference : https://m.blog.naver.com/55smile/221994292764

Packet Pool

Socket의 RW Buffer는 packet 단위로 송수신을 보장하지 않음
가장 쉬운 해결법은 packet의 크기를 담은 Header를 포함하여 전송한 후, Header-Content단위로 분리해서 Buffer로부터 읽어오는 방법

그러나 일반적으로 물리적인 거리가 멀어질수록 CPU time에서 많은 시간을 요구한다는 점을 감안해볼 때 NIC에서 Ram으로 데이터를 읽어오는 시간 역시 많은 CPU time을 요구할 것임을 짐작할 수 있음

또한, NIC이 바로 Ram으로 올린다 하더라도 Socket Buffer에서 User Buffer로 데이터를 옮기는 시간 역시 L3 Cache보다 먼 Ram사이에서 데이터가 전송되는 것이므로 마찬가지로 많은 CPU time을 요구할 것임

이러한 성능 저하를 해결하기 위해 Socket Buffer에 저장된 모든 데이터를 한번에 읽어온 후 Packet 단위로 분리, Header-Content로 분리, 불완전 전송된 Packet에 대한 저장 같은 작업을 할 수 있는 공간을 Packet Pool이라 함

Client의 경우 connect되는 socket의 개수가 많지 않아 굳이 절실하게 요구되지는 않지만, Server의 경우 다수의 사람이 연결된다면 구현하는 것이 좋음

입출력 모델

Multi Thread, Non-Blocking을 사용하지 않고도 Blocking하지 않게 socket 통신을 하는 방법
Blocking 함수지만 timeout이 존재하므로 빠져나올 수 있음
Select, SWASyncSelect 등이 있는데 Winsock에서만 지원하는 듯
최대 64개 socket만 지원하므로 client에서 사용한다면 큰 문제는 없을 듯
중요한건 Kernel에서 Socket의 송수신 완료 여부를 점검하며 Event driven하게 작동한다는 점

int iRet = WSAAsyncSelect(m_Sock, g_hWnd, 
NETWORK_MSG,									// User define custom message
FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);	// 발생시키고자 하는 event
LRESULT Sample::MsgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {  
    // user 가 정의한 Custom Message
    // #define Custom_Msg WM_USER + n
		case NETWORK_MSG :
		{
		if (WSAGETSELECTERROR(lParam) != 0)
		{
			PostQuitMessage(0);
			break;
		}
		WORD dwSelect = WSAGETSELECTEVENT(lParam);
		switch (dwSelect)
		{
        // Socket Descript set에 등록된 socket 중 발생한 event의 종류
		case FD_CONNECT:
			{
			int t = 0;
			}break;
		case FD_READ:
			{
				RecvThread();
			}break;
		case FD_WRITE:
			{
			int t = 0;
			}break;
		case FD_CLOSE:
			{
			int t = 0;
			}break;
		}
		}break;
}
Reference : https://dbehdrhs.tistory.com/84
profile
이상을 길잡이 삼아 로망을 추구합니다.

0개의 댓글