논블로킹 통신
논블로킹이란 서버가 무한정 기다리지 않고 다른 일을 하다가 연결을 시도하는 신호가 도착하거나 통신 메시지가 도착하면 사용자가 정의한 윈도우 메시지를 보내는 방식이다.
WSAAsyncSelect() 함수 : 윈도우 메시지, 네트워크 이벤트 등록 함수
int WSAAsyncSelect( SOCKET s, // 연결된 소켓 HWND hWnd, // 메시지가 발생하는 윈도우의 핸들 unsigned int wMsg, // 등록될 윈도우 메시지 long lEvent // 등록될 네트워크 이벤트 ); //성공시 0을 반환, 실패시 SOCKET_ERROR 반환 //네트워크 이벤트 enum NetworkEvent { FD_ACCEPT, //클라이언트가 접속하면 윈도우 메시지가 발생 FD_READ, //수신이 가능하면 윈도우 메시지가 발생 FD_WRITE, //송신이 가능하면 윈도우 메시지가 발생 FD_CLOSE, //접속을 종료하면 윈도우 메시지가 발생 FD_CONNECT, //접속이 완료되면 윈도우 메시지가 발생 FD_OOB //OOB 데이터가 도착하면 윈도우 메시지가 발생 }; |
WSAAsyncSelect( )함수를 이용하려면 먼저 윈도우 메시지를 등록해야 한다. 이것은 사용자 정의 윈도우 메시지로, 기존 윈도우 메시지와 메시지 번호가 동일하면 안 된다. 충돌을 방지하기 위해 다음과 같이 WM_USER를 사용한다. WM_USER는 메시지 정의를 위해 사용하며 숫자 2에는 다른 정수를 넣어도 된다.
#define WM_ASYNC WM_USER+2 |
WM_ASYNC 는 특정 네트워크 이벤트 발생시 윈도우 메시지로 사용한다.
네트워크 이벤트
FD_ACCEPT : 클라이언트가 접속하면 발생 FD_READ : 데이터 수신이 가능하면 발생 FD_WRITE : 데이터 송신이 가능하면 발생 FD_CLOSE : 상대가 접속을 종료하면 발생 FD_CONNECT : 접속이 완료되면 발생 FD_OOB : 통신과정에서 긴급히 전송되는OOB(out-of-band) 데이터가 도착하면 발생 |
논블로킹 단방향 통신 프로그램(서버)
#include <windows.h> #include <TCHAR.H> #include <stdio.h> #define WM_ASYNC WM_USER+2 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS WndClass; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra= 0; WndClass.cbWndExtra= 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = _T("Window Class Name"); RegisterClass(&WndClass); hwnd = CreateWindow( _T("Window Class Name"), _T("Server Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s, cs; static TCHAR msg[200]; static SOCKADDR_IN addr = { 0 }, c_addr; int size, msgLen; char buffer[100];
switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(s,(LPSOCKADDR)&addr, sizeof(addr)); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_ACCEPT); if (listen(s, 5) == -1) return 0; break; case WM_ASYNC: switch(lParam) { case FD_ACCEPT: size = sizeof(c_addr); cs = accept(s, (LPSOCKADDR)&c_addr, &size); WSAAsyncSelect(cs, hwnd, WM_ASYNC, FD_READ); break; case FD_READ: msgLen = recv(cs, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 0, 0, msg, (int)_tcslen(msg)); EndPaint(hwnd, &ps); break; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc (hwnd, iMsg, wParam, lParam); }
|
논블로킹 단방향 통신 프로그램(클라이언트)
#include <windows.h> #include <TCHAR.H> LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS WndClass; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra= 0; WndClass.cbWndExtra= 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = _T("Window Class Name"); RegisterClass(&WndClass); hwnd = CreateWindow( _T("Window Class Name"), _T("Client Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static WSADATA wsadata; static SOCKET s; static SOCKADDR_IN addr = { 0 }; switch (iMsg) { case WM_CREATE:
WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(s, (LPSOCKADDR)&addr, sizeof(addr)) == -1) return 0; break; case WM_KEYDOWN: send(s, "안녕 Server!", 13, 0); break; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } |
실행결과]
논블로킹 양방향 통신 프로그램(서버)
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s, cs; static TCHAR msg[200]; static SOCKADDR_IN addr = { 0 }, c_addr; int size, msgLen; char buffer[100];
switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(s,(LPSOCKADDR)&addr, sizeof(addr)); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_ACCEPT); if (listen(s, 5) == -1) return 0; break; case WM_ASYNC: switch(lParam) { case FD_ACCEPT: size = sizeof(c_addr); cs = accept(s, (LPSOCKADDR)&c_addr, &size); WSAAsyncSelect(cs, hwnd, WM_ASYNC, FD_READ); break; case FD_READ: msgLen = recv(cs, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 0, 0, msg, (int)_tcslen(msg)); EndPaint(hwnd, &ps); break; case WM_KEYDOWN: if (cs == INVALID_SOCKET) break; send(cs, "반가워 Client!", 15, 0); break; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); }
|
논블로킹 양방향 통신 프로그램(클라이언트)
#define WM_ASYNC WM_USER+2 ... { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s; static SOCKADDR_IN addr = { 0 }; static TCHAR msg[200]; int msgLen; char buffer[100]; switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2,2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_READ); if(connect(s, (LPSOCKADDR)&addr, sizeof(addr)) == -1) return 0; break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 0,0,msg, (int)_tcslen(msg)); EndPaint(hwnd, &ps); break; case WM_ASYNC: switch(lParam) { case FD_READ: msgLen = recv(s, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_KEYDOWN: send(s, "안녕 Server!", 13, 0); break; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc (hwnd, iMsg, wParam, lParam); } |
실행결과]
채팅 프로그램 만들기(서버)
#include <windows.h> #include <TCHAR.H> #include <stdio.h> #define WM_ASYNC WM_USER+2 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS WndClass; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = _T("Window Class Name"); RegisterClass(&WndClass); hwnd = CreateWindow(_T("Window Class Name"), _T("Server Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s, cs; static TCHAR msg[200]; static char buffer[100]; static SOCKADDR_IN addr = { 0 }, c_addr; static TCHAR str[100]; static int count; int size, msgLen;
switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(s,(LPSOCKADDR)&addr, sizeof(addr)); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_ACCEPT); if (listen(s, 5) == -1) return 0; break; case WM_ASYNC: switch(lParam) { case FD_ACCEPT: size = sizeof(c_addr); cs = accept(s, (LPSOCKADDR)&c_addr, &size); WSAAsyncSelect(cs, hwnd, WM_ASYNC, FD_READ); break; case FD_READ: msgLen = recv(cs, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (_tcscmp(msg, _T(""))) TextOut(hdc, 0, 30, msg, (int)_tcslen(msg)); TextOut(hdc, 0, 0, str, _tcslen(str)); EndPaint(hwnd, &ps); break; case WM_CHAR: if (wParam == VK_RETURN) if (cs == INVALID_SOCKET) return 0; else { #ifdef _UNICODE msgLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, str, -1, buffer, msgLen, NULL, NULL); #else strcpy_s(buffer, str); #endif send(cs, (LPSTR )buffer, strlen(buffer)+1, 0); count = 0; return 0; } str[count++] = wParam; str[count] = NULL; InvalidateRgn(hwnd, NULL, TRUE); return 0; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc (hwnd, iMsg, wParam, lParam); } |
채팅 프로그램 만들기(클라이언트)
#include <windows.h> #include <TCHAR.H> #include <stdio.h> #define WM_ASYNC WM_USER+2 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS WndClass; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = _T("Window Class Name"); RegisterClass(&WndClass); hwnd = CreateWindow(_T("Window Class Name"), _T("Server Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s; static SOCKADDR_IN addr = { 0 }; static TCHAR msg[200]; static TCHAR str[100]; static char buffer[100]; static int count; int msgLen;
switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_READ); if(connect(s, (LPSOCKADDR)&addr, sizeof(addr)) == -1) return 0; break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (_tcscmp(msg, _T(""))) TextOut(hdc, 0, 30, msg, (int)_tcslen(msg)); TextOut(hdc, 0,0, str,_tcslen(str)); EndPaint(hwnd, &ps); break; case WM_ASYNC: switch(lParam) { case FD_READ: msgLen = recv(s, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_CHAR: if (wParam == VK_RETURN) if (s == INVALID_SOCKET) return 0; else { #ifdef _UNICODE msgLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, str, -1, buffer, msgLen, NULL, NULL); #else strcpy_s(buffer, str); msgLen = strlen(buffer); #endif send(s, (LPSTR )buffer, msgLen+1, 0); count = 0; return 0; } str[count++] = wParam; str[count] = NULL; InvalidateRgn(hwnd, NULL, TRUE); return 0; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } |
한줄 채팅 프로그램 만들기(서버)
#include <windows.h> #include <TCHAR.H> #include <stdio.h> #define WM_ASYNC WM_USER+2 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS WndClass; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = _T("Window Class Name"); RegisterClass(&WndClass); hwnd = CreateWindow(_T("Window Class Name"), _T("Server Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s, cs; static TCHAR msg[200]; static char buffer[100]; static SOCKADDR_IN addr = { 0 }, c_addr; static TCHAR str[100]; static int count; int size, msgLen;
switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(s, (LPSOCKADDR)&addr, sizeof(addr)); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_ACCEPT); if (listen(s, 5) == -1) return 0; break; case WM_ASYNC: switch (lParam) { case FD_ACCEPT: size = sizeof(c_addr); cs = accept(s, (LPSOCKADDR)&c_addr, &size); WSAAsyncSelect(cs, hwnd, WM_ASYNC, FD_READ); break; case FD_READ: msgLen = recv(cs, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (_tcscmp(msg, _T(""))) TextOut(hdc, 0, 30, msg, (int)_tcslen(msg)); TextOut(hdc, 0, 0, str, _tcslen(str)); EndPaint(hwnd, &ps); break; case WM_CHAR: if (wParam == VK_RETURN) if (cs == INVALID_SOCKET) return 0; else { #ifdef _UNICODE msgLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, str, -1, buffer, msgLen, NULL, NULL); #else strcpy_s(buffer, str); #endif send(cs, (LPSTR)buffer, strlen(buffer) + 1, 0); count = 0; return 0; } str[count++] = wParam; str[count] = NULL; InvalidateRgn(hwnd, NULL, TRUE); return 0; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } |
한줄 채팅 프로그램 만들기(클라이언트)
#include <windows.h> #include <TCHAR.H> #define WM_ASYNC WM_USER+2 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS WndClass; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = _T("Window Class Name"); RegisterClass(&WndClass); hwnd = CreateWindow(_T("Window Class Name"), _T("Client Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static WSADATA wsadata; static SOCKET s; static SOCKADDR_IN addr = { 0 }; static TCHAR msg[200]; static TCHAR str[100]; static char buffer[100]; static int count; int msgLen;
switch (iMsg) { case WM_CREATE: WSAStartup(MAKEWORD(2, 2), &wsadata); s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = 20; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_READ); if (connect(s, (LPSOCKADDR)&addr, sizeof(addr)) == -1) return 0; break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (_tcscmp(msg, _T(""))) TextOut(hdc, 0, 30, msg, (int)_tcslen(msg)); TextOut(hdc, 0, 0, str, _tcslen(str)); EndPaint(hwnd, &ps); break; case WM_ASYNC: switch (lParam) { case FD_READ: msgLen = recv(s, buffer, 100, 0); buffer[msgLen] = NULL; #ifdef _UNICODE msgLen = MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), NULL, NULL); MultiByteToWideChar(CP_ACP, 0, buffer, strlen(buffer), msg, msgLen); msg[msgLen] = NULL; #else strcpy_s(msg, buffer); #endif InvalidateRgn(hwnd, NULL, TRUE); break; default: break; } break; case WM_CHAR: if (wParam == VK_RETURN) if (s == INVALID_SOCKET) return 0; else { #ifdef _UNICODE msgLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, str, -1, buffer, msgLen, NULL, NULL); #else strcpy_s(buffer, str); msgLen = strlen(buffer); #endif send(s, (LPSTR)buffer, msgLen + 1, 0); count = 0; return 0; } str[count++] = wParam; str[count] = NULL; InvalidateRgn(hwnd, NULL, TRUE); return 0; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } |
실행 결과]