편집 기록

편집 기록
  • 프로필 유동욱님의 편집
    날짜2018.12.02

    네트워크프로그래밍 gui..


      #pragma comment(lib, "ws2_32")
    
      #include <winsock2.h>
      #include <ws2tcpip.h>
      #include <windows.h>
      #include <stdlib.h>
      #include <stdio.h>
      #include "resource.h"
    
      #define SERVERIPV4  "127.0.0.1"
      #define SERVERIPV6  "::1"
      #define SERVERPORT  9000
    
      #define BUFSIZE     256                    // 전송 메시지 전체 크기
      #define MSGSIZE     (BUFSIZE-sizeof(int))  // 채팅 메시지 최대 길이
    
      #define CHATTING    1000                   // 메시지 타입: 채팅
      #define DRAWLINE    1001                   // 메시지 타입: 선 그리기
    
      #define WM_DRAWIT   (WM_USER+1)            // 사용자 정의 윈도우 메시지
    
    // 공통 메시지 형식
    // sizeof(COMM_MSG) == 256
    
    struct COMM_MSG
    {
    
        int  type;
        char dummy[MSGSIZE];
    };
    
    // 채팅 메시지 형식
    // sizeof(CHAT_MSG) == 256
    struct CHAT_MSG
    {
    
        int  type;
        char buf[MSGSIZE];
    };
    
    // sizeof(DRAWLINE_MSG) == 256
    // 선 그리기 메시지 형식
    
    
    struct DRAWLINE_MSG
    {
    
        int  type;
        int  color;
        int  x0, y0;
        int  x1, y1;
        char dummy[BUFSIZE - 6 * sizeof(int)];
    };
    
    static HINSTANCE     g_hInst; // 응용 프로그램 인스턴스 핸들
    
    static HWND          g_hDrawWnd; // 그림을 그릴 윈도우
    
    
    static HWND          g_hButtonSendMsg; // '메시지 전송' 버튼
    
    static HWND          g_hEditStatus; // 받은 메시지 출력
    
    static char          g_ipaddr[64]; // 서버 IP 주소
    
    static u_short       g_port; // 서버 포트 번호
    
    static BOOL          g_isIPv6; // IPv4 or IPv6 주소?
    
    static HANDLE        g_hClientThread; // 스레드 핸들
    
    static volatile BOOL g_bStart; // 통신 시작 여부
    
    static SOCKET        g_sock; // 클라이언트 소켓
    
    static HANDLE        g_hReadEvent, g_hWriteEvent; // 이벤트 핸들
    
    static CHAT_MSG      g_chatmsg; // 채팅 메시지 저장
    
    static DRAWLINE_MSG  g_drawmsg; // 선 그리기 메시지 저장
    
    static int           g_drawcolor; // 선 그리기 색상
    
    // 대화상자 프로시저
    
    BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
    
    // 소켓 통신 스레드 함수
    
    DWORD WINAPI ClientMain(LPVOID arg);
    DWORD WINAPI ReadThread(LPVOID arg);
    DWORD WINAPI WriteThread(LPVOID arg);
    
    // 자식 윈도우 프로시저
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    // 편집 컨트롤 출력 함수
    
    void DisplayText(const char *fmt, ...);
    
    // 사용자 정의 데이터 수신 함수
    
    int recvn(SOCKET s, char *buf, int len, int flags);
    
    // 오류 출력 함수
    
    void err_quit(const char *msg);
    void err_display(const char *msg);
    
    // 메인 함수
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
    {
    
        // 윈속 초기화
        WSADATA wsa;
        if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
    
        // 이벤트 생성
        g_hReadEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
        if (g_hReadEvent == NULL) return 1;
        g_hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (g_hWriteEvent == NULL) return 1;
    
        // 변수 초기화(일부)
        g_chatmsg.type = CHATTING;
        g_drawmsg.type = DRAWLINE;
        g_drawmsg.color = RGB(255, 0, 0);
    
        // 대화상자 생성
        g_hInst = hInstance;
        DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
    
        // 이벤트 제거
        CloseHandle(g_hReadEvent);
        CloseHandle(g_hWriteEvent);
    
        // 윈속 종료
        WSACleanup();
        return 0;
    }
    
    // 대화상자 프로시저
    
    BOOL CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    
        static HWND hButtonIsIPv6;
        static HWND hEditIPaddr;
        static HWND hEditPort;
        static HWND hButtonConnect;
        static HWND hEditMsg;
        static HWND hColorRed;
        static HWND hColorGreen;
        static HWND hColorBlue;
    
        switch (uMsg) {
        case WM_INITDIALOG:
            // 컨트롤 핸들 얻기
            hButtonIsIPv6 = GetDlgItem(hDlg, IDC_ISIPV6);
            hEditIPaddr = GetDlgItem(hDlg, IDC_IPADDR);
            hEditPort = GetDlgItem(hDlg, IDC_PORT);
            hButtonConnect = GetDlgItem(hDlg, IDC_CONNECT);
            g_hButtonSendMsg = GetDlgItem(hDlg, IDC_SENDMSG);
            hEditMsg = GetDlgItem(hDlg, IDC_MSG);
            g_hEditStatus = GetDlgItem(hDlg, IDC_STATUS);
            hColorRed = GetDlgItem(hDlg, IDC_COLORRED);
            hColorGreen = GetDlgItem(hDlg, IDC_COLORGREEN);
            hColorBlue = GetDlgItem(hDlg, IDC_COLORBLUE);
    
            // 컨트롤 초기화
            SendMessage(hEditMsg, EM_SETLIMITTEXT, MSGSIZE, 0);
            EnableWindow(g_hButtonSendMsg, FALSE);
            SetDlgItemText(hDlg, IDC_IPADDR, SERVERIPV4);
            SetDlgItemInt(hDlg, IDC_PORT, SERVERPORT, FALSE);
            SendMessage(hColorRed, BM_SETCHECK, BST_CHECKED, 0);
            SendMessage(hColorGreen, BM_SETCHECK, BST_UNCHECKED, 0);
            SendMessage(hColorBlue, BM_SETCHECK, BST_UNCHECKED, 0);
    
            // 윈도우 클래스 등록
            WNDCLASS wndclass;
            wndclass.style = CS_HREDRAW | CS_VREDRAW;
            wndclass.lpfnWndProc = WndProc;
            wndclass.cbClsExtra = 0;
            wndclass.cbWndExtra = 0;
            wndclass.hInstance = g_hInst;
            wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
            wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
            wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
            wndclass.lpszMenuName = NULL;
            wndclass.lpszClassName = "MyWndClass";
            if (!RegisterClass(&wndclass)) return 1;
    
            // 자식 윈도우 생성
            g_hDrawWnd = CreateWindow("MyWndClass", "그림 그릴 윈도우", WS_CHILD,
                450, 38, 425, 415, hDlg, (HMENU)NULL, g_hInst, NULL);
            if (g_hDrawWnd == NULL) return 1;
            ShowWindow(g_hDrawWnd, SW_SHOW);
            UpdateWindow(g_hDrawWnd);
    
            return TRUE;
    
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
            case IDC_ISIPV6:
                g_isIPv6 = SendMessage(hButtonIsIPv6, BM_GETCHECK, 0, 0);
                if (g_isIPv6 == false)
                    SetDlgItemText(hDlg, IDC_IPADDR, SERVERIPV4);
                else
                    SetDlgItemText(hDlg, IDC_IPADDR, SERVERIPV6);
                return TRUE;
    
            case IDC_CONNECT:
                GetDlgItemText(hDlg, IDC_IPADDR, g_ipaddr, sizeof(g_ipaddr));
                g_port = GetDlgItemInt(hDlg, IDC_PORT, NULL, FALSE);
                g_isIPv6 = SendMessage(hButtonIsIPv6, BM_GETCHECK, 0, 0);
    
                // 소켓 통신 스레드 시작
                g_hClientThread = CreateThread(NULL, 0, ClientMain, NULL, 0, NULL);
                if (g_hClientThread == NULL) {
                    MessageBox(hDlg, "클라이언트를 시작할 수 없습니다."
                        "\r\n프로그램을 종료합니다.", "실패!", MB_ICONERROR);
                    EndDialog(hDlg, 0);
                }
                else {
                    EnableWindow(hButtonConnect, FALSE);
                    while (g_bStart == FALSE); // 서버 접속 성공 기다림
                    EnableWindow(hButtonIsIPv6, FALSE);
                    EnableWindow(hEditIPaddr, FALSE);
                    EnableWindow(hEditPort, FALSE);
                    EnableWindow(g_hButtonSendMsg, TRUE);
                    SetFocus(hEditMsg);
                }
                return TRUE;
    
            case IDC_SENDMSG:
                // 읽기 완료를 기다림
                WaitForSingleObject(g_hReadEvent, INFINITE);
                GetDlgItemText(hDlg, IDC_MSG, g_chatmsg.buf, MSGSIZE);
                // 쓰기 완료를 알림
                SetEvent(g_hWriteEvent);
                // 입력된 텍스트 전체를 선택 표시
                SendMessage(hEditMsg, EM_SETSEL, 0, -1);
                return TRUE;
    
            case IDC_COLORRED:
                g_drawmsg.color = RGB(255, 0, 0);
                return TRUE;
    
            case IDC_COLORGREEN:
                g_drawmsg.color = RGB(0, 255, 0);
                return TRUE;
    
            case IDC_COLORBLUE:
                g_drawmsg.color = RGB(0, 0, 255);
                return TRUE;
    
            case IDCANCEL:
                if (MessageBox(hDlg, "정말로 종료하시겠습니까?",
                    "질문", MB_YESNO | MB_ICONQUESTION) == IDYES)
                {
                    closesocket(g_sock);
                    EndDialog(hDlg, IDCANCEL);
                }
                return TRUE;
    
            }
            return FALSE;
        }
    
        return FALSE;
    }
    
    // 소켓 통신 스레드 함수
    
    DWORD WINAPI ClientMain(LPVOID arg)
    {
    
        int retval;
    
        if (g_isIPv6 == false) {
            // socket()
            g_sock = socket(AF_INET, SOCK_STREAM, 0);
            if (g_sock == INVALID_SOCKET) err_quit("socket()");
    
            // connect()
            SOCKADDR_IN serveraddr;
            ZeroMemory(&serveraddr, sizeof(serveraddr));
            serveraddr.sin_family = AF_INET;
            serveraddr.sin_addr.s_addr = inet_addr(g_ipaddr);
            serveraddr.sin_port = htons(g_port);
            retval = connect(g_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr));
            if (retval == SOCKET_ERROR) err_quit("connect()");
        }
        else {
            // socket()
            g_sock = socket(AF_INET6, SOCK_STREAM, 0);
            if (g_sock == INVALID_SOCKET) err_quit("socket()");
    
            // connect()
            SOCKADDR_IN6 serveraddr;
            ZeroMemory(&serveraddr, sizeof(serveraddr));
            serveraddr.sin6_family = AF_INET6;
            int addrlen = sizeof(serveraddr);
            WSAStringToAddress(g_ipaddr, AF_INET6, NULL,
                (SOCKADDR *)&serveraddr, &addrlen);
            serveraddr.sin6_port = htons(g_port);
            retval = connect(g_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr));
            if (retval == SOCKET_ERROR) err_quit("connect()");
        }
        MessageBox(NULL, "서버에 접속했습니다.", "성공!", MB_ICONINFORMATION);
    
        // 읽기 & 쓰기 스레드 생성
        HANDLE hThread[2];
        hThread[0] = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);
        hThread[1] = CreateThread(NULL, 0, WriteThread, NULL, 0, NULL);
        if (hThread[0] == NULL || hThread[1] == NULL) {
            MessageBox(NULL, "스레드를 시작할 수 없습니다."
                "\r\n프로그램을 종료합니다.",
                "실패!", MB_ICONERROR);
            exit(1);
        }
    
        g_bStart = TRUE;
    
        // 스레드 종료 대기
        retval = WaitForMultipleObjects(2, hThread, FALSE, INFINITE);
        retval -= WAIT_OBJECT_0;
        if (retval == 0)
            TerminateThread(hThread[1], 1);
        else
            TerminateThread(hThread[0], 1);
        CloseHandle(hThread[0]);
        CloseHandle(hThread[1]);
    
        g_bStart = FALSE;
    
        MessageBox(NULL, "서버가 접속을 끊었습니다", "알림", MB_ICONINFORMATION);
        EnableWindow(g_hButtonSendMsg, FALSE);
    
        closesocket(g_sock);
        return 0;
    }
    
    // 데이터 받기
    
    DWORD WINAPI ReadThread(LPVOID arg)
    {
    
        int retval;
        COMM_MSG comm_msg;
        CHAT_MSG *chat_msg;
        DRAWLINE_MSG *draw_msg;
    
        while (1) {
            retval = recvn(g_sock, (char *)&comm_msg, BUFSIZE, 0);
            if (retval == 0 || retval == SOCKET_ERROR) {
                break;
            }
    
            if (comm_msg.type == CHATTING) {
                chat_msg = (CHAT_MSG *)&comm_msg;
                DisplayText("[받은 메시지] %s\r\n", chat_msg->buf);
            }
    
            else if (comm_msg.type == DRAWLINE) {
                draw_msg = (DRAWLINE_MSG *)&comm_msg;
                g_drawcolor = draw_msg->color;
                SendMessage(g_hDrawWnd, WM_DRAWIT,
                    MAKEWPARAM(draw_msg->x0, draw_msg->y0),
                    MAKELPARAM(draw_msg->x1, draw_msg->y1));
            }
        }
    
        return 0;
    }
    
    // 데이터 보내기
    
    DWORD WINAPI WriteThread(LPVOID arg)
    {
    
        int retval;
    
        // 서버와 데이터 통신
        while (1) {
            // 쓰기 완료 기다리기
            WaitForSingleObject(g_hWriteEvent, INFINITE);
    
            // 문자열 길이가 0이면 보내지 않음
            if (strlen(g_chatmsg.buf) == 0) {
                // '메시지 전송' 버튼 활성화
                EnableWindow(g_hButtonSendMsg, TRUE);
                // 읽기 완료 알리기
                SetEvent(g_hReadEvent);
                continue;
            }
    
            // 데이터 보내기
            retval = send(g_sock, (char *)&g_chatmsg, BUFSIZE, 0);
            if (retval == SOCKET_ERROR) {
                break;
            }
    
            // '메시지 전송' 버튼 활성화
            EnableWindow(g_hButtonSendMsg, TRUE);
            // 읽기 완료 알리기
            SetEvent(g_hReadEvent);
        }
    
        return 0;
    }
    
    // 자식 윈도우 프로시저
    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    
        HDC hDC;
        int cx, cy;
        PAINTSTRUCT ps;
        RECT rect;
        HPEN hPen, hOldPen;
        static HBITMAP hBitmap;
        static HDC hDCMem;
        static int x0, y0;
        static int x1, y1;
        static BOOL bDrawing = FALSE;
    
        switch (uMsg) {
        case WM_CREATE:
            hDC = GetDC(hWnd);
    
            // 화면을 저장할 비트맵 생성
            cx = GetDeviceCaps(hDC, HORZRES);
            cy = GetDeviceCaps(hDC, VERTRES);
            hBitmap = CreateCompatibleBitmap(hDC, cx, cy);
    
            // 메모리 DC 생성
            hDCMem = CreateCompatibleDC(hDC);
    
            // 비트맵 선택 후 메모리 DC 화면을 흰색으로 칠함
            SelectObject(hDCMem, hBitmap);
            SelectObject(hDCMem, GetStockObject(WHITE_BRUSH));
            SelectObject(hDCMem, GetStockObject(WHITE_PEN));
            Rectangle(hDCMem, 0, 0, cx, cy);
    
            ReleaseDC(hWnd, hDC);
            return 0;
        case WM_LBUTTONDOWN:
            x0 = LOWORD(lParam);
            y0 = HIWORD(lParam);
            bDrawing = TRUE;
            return 0;
        case WM_MOUSEMOVE:
            if (bDrawing && g_bStart) {
                x1 = LOWORD(lParam);
                y1 = HIWORD(lParam);
    
                // 선 그리기 메시지 보내기
                g_drawmsg.x0 = x0;
                g_drawmsg.y0 = y0;
                g_drawmsg.x1 = x1;
                g_drawmsg.y1 = y1;
                send(g_sock, (char *)&g_drawmsg, BUFSIZE, 0);
    
                x0 = x1;
                y0 = y1;
            }
            return 0;
        case WM_LBUTTONUP:
            bDrawing = FALSE;
            return 0;
        case WM_DRAWIT:
            hDC = GetDC(hWnd);
            hPen = CreatePen(PS_SOLID, 3, g_drawcolor);
    
            // 화면에 그리기
            hOldPen = (HPEN)SelectObject(hDC, hPen);
            MoveToEx(hDC, LOWORD(wParam), HIWORD(wParam), NULL);
            LineTo(hDC, LOWORD(lParam), HIWORD(lParam));
            SelectObject(hDC, hOldPen);
    
            // 메모리 비트맵에 그리기
            hOldPen = (HPEN)SelectObject(hDCMem, hPen);
            MoveToEx(hDCMem, LOWORD(wParam), HIWORD(wParam), NULL);
            LineTo(hDCMem, LOWORD(lParam), HIWORD(lParam));
            SelectObject(hDC, hOldPen);
    
            DeleteObject(hPen);
            ReleaseDC(hWnd, hDC);
            return 0;
        case WM_PAINT:
            hDC = BeginPaint(hWnd, &ps);
    
            // 메모리 비트맵에 저장된 그림을 화면에 전송
            GetClientRect(hWnd, &rect);
            BitBlt(hDC, 0, 0, rect.right - rect.left,
                rect.bottom - rect.top, hDCMem, 0, 0, SRCCOPY);
    
            EndPaint(hWnd, &ps);
            return 0;
        case WM_DESTROY:
            DeleteObject(hBitmap);
            DeleteDC(hDCMem);
            PostQuitMessage(0);
            return 0;
        }
    
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    // 에디트 컨트롤에 문자열 출력
    void DisplayText(const char *fmt, ...)
    {
        va_list arg;
        va_start(arg, fmt);
    
        char cbuf[1024];
        vsprintf(cbuf, fmt, arg);
    
        int nLength = GetWindowTextLength(g_hEditStatus);
        SendMessage(g_hEditStatus, EM_SETSEL, nLength, nLength);
        SendMessage(g_hEditStatus, EM_REPLACESEL, FALSE, (LPARAM)cbuf);
    
        va_end(arg);
    }
    
    // 사용자 정의 데이터 수신 함수
    int recvn(SOCKET s, char *buf, int len, int flags)
    {
        int received;
        char *ptr = buf;
        int left = len;
    
        while (left > 0) {
            received = recv(s, ptr, left, flags);
            if (received == SOCKET_ERROR)
                return SOCKET_ERROR;
            else if (received == 0)
                break;
            left -= received;
            ptr += received;
        }
    
        return (len - left);
    }
    
    // 소켓 함수 오류 출력 후 종료
    
    void err_quit(const char *msg)
    {
    
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL, WSAGetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf, 0, NULL);
        MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
        LocalFree(lpMsgBuf);
        exit(1);
    }
    
    // 소켓 함수 오류 출력
    
    void err_display(const char *msg)
    {
    
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL, WSAGetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf, 0, NULL);
        printf("[%s] %s", msg, (char *)lpMsgBuf);
        LocalFree(lpMsgBuf);
    }
    

    //{{NO_DEPENDENCIES}}
    // Microsoft Developer Studio generated include file.
    // Used by PrjClient.rc
    //
    
    
     #define IDD_DIALOG1                     101
    
     #define IDC_ISIPV6                      1001
    
     #define IDC_IPADDR                      1002
    
     #define IDC_PORT                        1003
    
     #define IDC_CONNECT                     1004
    
     #define IDC_MSG                         1005
    
     #define IDC_STATUS                      1006
    
     #define IDC_SENDMSG                     1007
    
     #define IDC_COLORRED                    1010
    
     #define IDC_COLORGREEN                  1011
    
     #define IDC_COLORBLUE                   1012
    
    
    
    // Next default values for new objects
    
    //
    
     #ifdef APSTUDIO_INVOKED
    
     #ifndef APSTUDIO_READONLY_SYMBOLS
    
     #define _APS_NEXT_RESOURCE_VALUE        102
    
     #define _APS_NEXT_COMMAND_VALUE         40001
    
     #define _APS_NEXT_CONTROL_VALUE         1013
    
     #define _APS_NEXT_SYMED_VALUE           101
    
     #endif
    
     #endif
    

    이파일이.. 오류는전부없어졌는데 실행을해도 콘솔창도안나오고.. 빌드는되는데 아무창도 뜨질않네요.. 비주얼스튜디오 2017입니다. 헤더파일도 cpp파일이랑 같은경로에 넣어놨습니다.

    몇번 빌드했더니 이제 빌드했다고 밑에 창에 메시지도안나오고.. 멈추진않앗는데 아무동작을 안하네요 ㅜㅜㅜ

    왜그런건가요

  • 프로필 알 수 없는 사용자님의 편집
    날짜2018.12.01

    네트워크프로그래밍 gui..


    #pragma comment(lib, "ws2_32")

    #include #include #include #include #include #include "resource.h"

    #define SERVERIPV4 "127.0.0.1" #define SERVERIPV6 "::1" #define SERVERPORT 9000

    #define BUFSIZE 256 // 전송 메시지 전체 크기 #define MSGSIZE (BUFSIZE-sizeof(int)) // 채팅 메시지 최대 길이

    #define CHATTING 1000 // 메시지 타입: 채팅 #define DRAWLINE 1001 // 메시지 타입: 선 그리기

    #define WM_DRAWIT (WM_USER+1) // 사용자 정의 윈도우 메시지

    // 공통 메시지 형식 // sizeof(COMM_MSG) == 256

    struct COMM_MSG {

    int  type;
    char dummy[MSGSIZE];
    

    };

    // 채팅 메시지 형식 // sizeof(CHAT_MSG) == 256 struct CHAT_MSG {

    int  type;
    char buf[MSGSIZE];
    

    };

    // sizeof(DRAWLINE_MSG) == 256 // 선 그리기 메시지 형식

    struct DRAWLINE_MSG {

    int  type;
    int  color;
    int  x0, y0;
    int  x1, y1;
    char dummy[BUFSIZE - 6 * sizeof(int)];
    

    };

    static HINSTANCE g_hInst; // 응용 프로그램 인스턴스 핸들

    static HWND g_hDrawWnd; // 그림을 그릴 윈도우

    static HWND g_hButtonSendMsg; // '메시지 전송' 버튼

    static HWND g_hEditStatus; // 받은 메시지 출력

    static char g_ipaddr[64]; // 서버 IP 주소

    static u_short g_port; // 서버 포트 번호

    static BOOL g_isIPv6; // IPv4 or IPv6 주소?

    static HANDLE g_hClientThread; // 스레드 핸들

    static volatile BOOL g_bStart; // 통신 시작 여부

    static SOCKET g_sock; // 클라이언트 소켓

    static HANDLE g_hReadEvent, g_hWriteEvent; // 이벤트 핸들

    static CHAT_MSG g_chatmsg; // 채팅 메시지 저장

    static DRAWLINE_MSG g_drawmsg; // 선 그리기 메시지 저장

    static int g_drawcolor; // 선 그리기 색상

    // 대화상자 프로시저

    BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

    // 소켓 통신 스레드 함수

    DWORD WINAPI ClientMain(LPVOID arg); DWORD WINAPI ReadThread(LPVOID arg); DWORD WINAPI WriteThread(LPVOID arg);

    // 자식 윈도우 프로시저

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

    // 편집 컨트롤 출력 함수

    void DisplayText(const char *fmt, ...);

    // 사용자 정의 데이터 수신 함수

    int recvn(SOCKET s, char *buf, int len, int flags);

    // 오류 출력 함수

    void err_quit(const char *msg); void err_display(const char *msg);

    // 메인 함수

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    // 윈속 초기화
    WSADATA wsa;
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
    
    // 이벤트 생성
    g_hReadEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
    if (g_hReadEvent == NULL) return 1;
    g_hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (g_hWriteEvent == NULL) return 1;
    
    // 변수 초기화(일부)
    g_chatmsg.type = CHATTING;
    g_drawmsg.type = DRAWLINE;
    g_drawmsg.color = RGB(255, 0, 0);
    
    // 대화상자 생성
    g_hInst = hInstance;
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
    
    // 이벤트 제거
    CloseHandle(g_hReadEvent);
    CloseHandle(g_hWriteEvent);
    
    // 윈속 종료
    WSACleanup();
    return 0;
    

    }

    // 대화상자 프로시저

    BOOL CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    static HWND hButtonIsIPv6;
    static HWND hEditIPaddr;
    static HWND hEditPort;
    static HWND hButtonConnect;
    static HWND hEditMsg;
    static HWND hColorRed;
    static HWND hColorGreen;
    static HWND hColorBlue;
    
    switch (uMsg) {
    case WM_INITDIALOG:
        // 컨트롤 핸들 얻기
        hButtonIsIPv6 = GetDlgItem(hDlg, IDC_ISIPV6);
        hEditIPaddr = GetDlgItem(hDlg, IDC_IPADDR);
        hEditPort = GetDlgItem(hDlg, IDC_PORT);
        hButtonConnect = GetDlgItem(hDlg, IDC_CONNECT);
        g_hButtonSendMsg = GetDlgItem(hDlg, IDC_SENDMSG);
        hEditMsg = GetDlgItem(hDlg, IDC_MSG);
        g_hEditStatus = GetDlgItem(hDlg, IDC_STATUS);
        hColorRed = GetDlgItem(hDlg, IDC_COLORRED);
        hColorGreen = GetDlgItem(hDlg, IDC_COLORGREEN);
        hColorBlue = GetDlgItem(hDlg, IDC_COLORBLUE);
    
        // 컨트롤 초기화
        SendMessage(hEditMsg, EM_SETLIMITTEXT, MSGSIZE, 0);
        EnableWindow(g_hButtonSendMsg, FALSE);
        SetDlgItemText(hDlg, IDC_IPADDR, SERVERIPV4);
        SetDlgItemInt(hDlg, IDC_PORT, SERVERPORT, FALSE);
        SendMessage(hColorRed, BM_SETCHECK, BST_CHECKED, 0);
        SendMessage(hColorGreen, BM_SETCHECK, BST_UNCHECKED, 0);
        SendMessage(hColorBlue, BM_SETCHECK, BST_UNCHECKED, 0);
    
        // 윈도우 클래스 등록
        WNDCLASS wndclass;
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = g_hInst;
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = NULL;
        wndclass.lpszClassName = "MyWndClass";
        if (!RegisterClass(&wndclass)) return 1;
    
        // 자식 윈도우 생성
        g_hDrawWnd = CreateWindow("MyWndClass", "그림 그릴 윈도우", WS_CHILD,
            450, 38, 425, 415, hDlg, (HMENU)NULL, g_hInst, NULL);
        if (g_hDrawWnd == NULL) return 1;
        ShowWindow(g_hDrawWnd, SW_SHOW);
        UpdateWindow(g_hDrawWnd);
    
        return TRUE;
    
    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDC_ISIPV6:
            g_isIPv6 = SendMessage(hButtonIsIPv6, BM_GETCHECK, 0, 0);
            if (g_isIPv6 == false)
                SetDlgItemText(hDlg, IDC_IPADDR, SERVERIPV4);
            else
                SetDlgItemText(hDlg, IDC_IPADDR, SERVERIPV6);
            return TRUE;
    
        case IDC_CONNECT:
            GetDlgItemText(hDlg, IDC_IPADDR, g_ipaddr, sizeof(g_ipaddr));
            g_port = GetDlgItemInt(hDlg, IDC_PORT, NULL, FALSE);
            g_isIPv6 = SendMessage(hButtonIsIPv6, BM_GETCHECK, 0, 0);
    
            // 소켓 통신 스레드 시작
            g_hClientThread = CreateThread(NULL, 0, ClientMain, NULL, 0, NULL);
            if (g_hClientThread == NULL) {
                MessageBox(hDlg, "클라이언트를 시작할 수 없습니다."
                    "\r\n프로그램을 종료합니다.", "실패!", MB_ICONERROR);
                EndDialog(hDlg, 0);
            }
            else {
                EnableWindow(hButtonConnect, FALSE);
                while (g_bStart == FALSE); // 서버 접속 성공 기다림
                EnableWindow(hButtonIsIPv6, FALSE);
                EnableWindow(hEditIPaddr, FALSE);
                EnableWindow(hEditPort, FALSE);
                EnableWindow(g_hButtonSendMsg, TRUE);
                SetFocus(hEditMsg);
            }
            return TRUE;
    
        case IDC_SENDMSG:
            // 읽기 완료를 기다림
            WaitForSingleObject(g_hReadEvent, INFINITE);
            GetDlgItemText(hDlg, IDC_MSG, g_chatmsg.buf, MSGSIZE);
            // 쓰기 완료를 알림
            SetEvent(g_hWriteEvent);
            // 입력된 텍스트 전체를 선택 표시
            SendMessage(hEditMsg, EM_SETSEL, 0, -1);
            return TRUE;
    
        case IDC_COLORRED:
            g_drawmsg.color = RGB(255, 0, 0);
            return TRUE;
    
        case IDC_COLORGREEN:
            g_drawmsg.color = RGB(0, 255, 0);
            return TRUE;
    
        case IDC_COLORBLUE:
            g_drawmsg.color = RGB(0, 0, 255);
            return TRUE;
    
        case IDCANCEL:
            if (MessageBox(hDlg, "정말로 종료하시겠습니까?",
                "질문", MB_YESNO | MB_ICONQUESTION) == IDYES)
            {
                closesocket(g_sock);
                EndDialog(hDlg, IDCANCEL);
            }
            return TRUE;
    
        }
        return FALSE;
    }
    
    return FALSE;
    

    }

    // 소켓 통신 스레드 함수

    DWORD WINAPI ClientMain(LPVOID arg) {

    int retval;
    
    if (g_isIPv6 == false) {
        // socket()
        g_sock = socket(AF_INET, SOCK_STREAM, 0);
        if (g_sock == INVALID_SOCKET) err_quit("socket()");
    
        // connect()
        SOCKADDR_IN serveraddr;
        ZeroMemory(&serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr(g_ipaddr);
        serveraddr.sin_port = htons(g_port);
        retval = connect(g_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr));
        if (retval == SOCKET_ERROR) err_quit("connect()");
    }
    else {
        // socket()
        g_sock = socket(AF_INET6, SOCK_STREAM, 0);
        if (g_sock == INVALID_SOCKET) err_quit("socket()");
    
        // connect()
        SOCKADDR_IN6 serveraddr;
        ZeroMemory(&serveraddr, sizeof(serveraddr));
        serveraddr.sin6_family = AF_INET6;
        int addrlen = sizeof(serveraddr);
        WSAStringToAddress(g_ipaddr, AF_INET6, NULL,
            (SOCKADDR *)&serveraddr, &addrlen);
        serveraddr.sin6_port = htons(g_port);
        retval = connect(g_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr));
        if (retval == SOCKET_ERROR) err_quit("connect()");
    }
    MessageBox(NULL, "서버에 접속했습니다.", "성공!", MB_ICONINFORMATION);
    
    // 읽기 & 쓰기 스레드 생성
    HANDLE hThread[2];
    hThread[0] = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);
    hThread[1] = CreateThread(NULL, 0, WriteThread, NULL, 0, NULL);
    if (hThread[0] == NULL || hThread[1] == NULL) {
        MessageBox(NULL, "스레드를 시작할 수 없습니다."
            "\r\n프로그램을 종료합니다.",
            "실패!", MB_ICONERROR);
        exit(1);
    }
    
    g_bStart = TRUE;
    
    // 스레드 종료 대기
    retval = WaitForMultipleObjects(2, hThread, FALSE, INFINITE);
    retval -= WAIT_OBJECT_0;
    if (retval == 0)
        TerminateThread(hThread[1], 1);
    else
        TerminateThread(hThread[0], 1);
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
    
    g_bStart = FALSE;
    
    MessageBox(NULL, "서버가 접속을 끊었습니다", "알림", MB_ICONINFORMATION);
    EnableWindow(g_hButtonSendMsg, FALSE);
    
    closesocket(g_sock);
    return 0;
    

    }

    // 데이터 받기

    DWORD WINAPI ReadThread(LPVOID arg) {

    int retval;
    COMM_MSG comm_msg;
    CHAT_MSG *chat_msg;
    DRAWLINE_MSG *draw_msg;
    
    while (1) {
        retval = recvn(g_sock, (char *)&comm_msg, BUFSIZE, 0);
        if (retval == 0 || retval == SOCKET_ERROR) {
            break;
        }
    
        if (comm_msg.type == CHATTING) {
            chat_msg = (CHAT_MSG *)&comm_msg;
            DisplayText("[받은 메시지] %s\r\n", chat_msg->buf);
        }
    
        else if (comm_msg.type == DRAWLINE) {
            draw_msg = (DRAWLINE_MSG *)&comm_msg;
            g_drawcolor = draw_msg->color;
            SendMessage(g_hDrawWnd, WM_DRAWIT,
                MAKEWPARAM(draw_msg->x0, draw_msg->y0),
                MAKELPARAM(draw_msg->x1, draw_msg->y1));
        }
    }
    
    return 0;
    

    }

    // 데이터 보내기

    DWORD WINAPI WriteThread(LPVOID arg) {

    int retval;
    
    // 서버와 데이터 통신
    while (1) {
        // 쓰기 완료 기다리기
        WaitForSingleObject(g_hWriteEvent, INFINITE);
    
        // 문자열 길이가 0이면 보내지 않음
        if (strlen(g_chatmsg.buf) == 0) {
            // '메시지 전송' 버튼 활성화
            EnableWindow(g_hButtonSendMsg, TRUE);
            // 읽기 완료 알리기
            SetEvent(g_hReadEvent);
            continue;
        }
    
        // 데이터 보내기
        retval = send(g_sock, (char *)&g_chatmsg, BUFSIZE, 0);
        if (retval == SOCKET_ERROR) {
            break;
        }
    
        // '메시지 전송' 버튼 활성화
        EnableWindow(g_hButtonSendMsg, TRUE);
        // 읽기 완료 알리기
        SetEvent(g_hReadEvent);
    }
    
    return 0;
    

    }

    // 자식 윈도우 프로시저 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    HDC hDC;
    int cx, cy;
    PAINTSTRUCT ps;
    RECT rect;
    HPEN hPen, hOldPen;
    static HBITMAP hBitmap;
    static HDC hDCMem;
    static int x0, y0;
    static int x1, y1;
    static BOOL bDrawing = FALSE;
    
    switch (uMsg) {
    case WM_CREATE:
        hDC = GetDC(hWnd);
    
        // 화면을 저장할 비트맵 생성
        cx = GetDeviceCaps(hDC, HORZRES);
        cy = GetDeviceCaps(hDC, VERTRES);
        hBitmap = CreateCompatibleBitmap(hDC, cx, cy);
    
        // 메모리 DC 생성
        hDCMem = CreateCompatibleDC(hDC);
    
        // 비트맵 선택 후 메모리 DC 화면을 흰색으로 칠함
        SelectObject(hDCMem, hBitmap);
        SelectObject(hDCMem, GetStockObject(WHITE_BRUSH));
        SelectObject(hDCMem, GetStockObject(WHITE_PEN));
        Rectangle(hDCMem, 0, 0, cx, cy);
    
        ReleaseDC(hWnd, hDC);
        return 0;
    case WM_LBUTTONDOWN:
        x0 = LOWORD(lParam);
        y0 = HIWORD(lParam);
        bDrawing = TRUE;
        return 0;
    case WM_MOUSEMOVE:
        if (bDrawing && g_bStart) {
            x1 = LOWORD(lParam);
            y1 = HIWORD(lParam);
    
            // 선 그리기 메시지 보내기
            g_drawmsg.x0 = x0;
            g_drawmsg.y0 = y0;
            g_drawmsg.x1 = x1;
            g_drawmsg.y1 = y1;
            send(g_sock, (char *)&g_drawmsg, BUFSIZE, 0);
    
            x0 = x1;
            y0 = y1;
        }
        return 0;
    case WM_LBUTTONUP:
        bDrawing = FALSE;
        return 0;
    case WM_DRAWIT:
        hDC = GetDC(hWnd);
        hPen = CreatePen(PS_SOLID, 3, g_drawcolor);
    
        // 화면에 그리기
        hOldPen = (HPEN)SelectObject(hDC, hPen);
        MoveToEx(hDC, LOWORD(wParam), HIWORD(wParam), NULL);
        LineTo(hDC, LOWORD(lParam), HIWORD(lParam));
        SelectObject(hDC, hOldPen);
    
        // 메모리 비트맵에 그리기
        hOldPen = (HPEN)SelectObject(hDCMem, hPen);
        MoveToEx(hDCMem, LOWORD(wParam), HIWORD(wParam), NULL);
        LineTo(hDCMem, LOWORD(lParam), HIWORD(lParam));
        SelectObject(hDC, hOldPen);
    
        DeleteObject(hPen);
        ReleaseDC(hWnd, hDC);
        return 0;
    case WM_PAINT:
        hDC = BeginPaint(hWnd, &ps);
    
        // 메모리 비트맵에 저장된 그림을 화면에 전송
        GetClientRect(hWnd, &rect);
        BitBlt(hDC, 0, 0, rect.right - rect.left,
            rect.bottom - rect.top, hDCMem, 0, 0, SRCCOPY);
    
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        DeleteObject(hBitmap);
        DeleteDC(hDCMem);
        PostQuitMessage(0);
        return 0;
    }
    
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
    

    }

    // 에디트 컨트롤에 문자열 출력 void DisplayText(const char *fmt, ...) { va_list arg; va_start(arg, fmt);

    char cbuf[1024];
    vsprintf(cbuf, fmt, arg);
    
    int nLength = GetWindowTextLength(g_hEditStatus);
    SendMessage(g_hEditStatus, EM_SETSEL, nLength, nLength);
    SendMessage(g_hEditStatus, EM_REPLACESEL, FALSE, (LPARAM)cbuf);
    
    va_end(arg);
    

    }

    // 사용자 정의 데이터 수신 함수 int recvn(SOCKET s, char *buf, int len, int flags) { int received; char *ptr = buf; int left = len;

    while (left > 0) {
        received = recv(s, ptr, left, flags);
        if (received == SOCKET_ERROR)
            return SOCKET_ERROR;
        else if (received == 0)
            break;
        left -= received;
        ptr += received;
    }
    
    return (len - left);
    

    }

    // 소켓 함수 오류 출력 후 종료

    void err_quit(const char *msg) {

    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, WSAGetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf, 0, NULL);
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
    LocalFree(lpMsgBuf);
    exit(1);
    

    }

    // 소켓 함수 오류 출력

    void err_display(const char *msg) {

    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, WSAGetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf, 0, NULL);
    printf("[%s] %s", msg, (char *)lpMsgBuf);
    LocalFree(lpMsgBuf);
    

    }


    //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by PrjClient.rc //

    #define IDD_DIALOG1 101

    #define IDC_ISIPV6 1001

    #define IDC_IPADDR 1002

    #define IDC_PORT 1003

    #define IDC_CONNECT 1004

    #define IDC_MSG 1005

    #define IDC_STATUS 1006

    #define IDC_SENDMSG 1007

    #define IDC_COLORRED 1010

    #define IDC_COLORGREEN 1011

    #define IDC_COLORBLUE 1012

    // Next default values for new objects

    //

    #ifdef APSTUDIO_INVOKED

    #ifndef APSTUDIO_READONLY_SYMBOLS

    #define _APS_NEXT_RESOURCE_VALUE 102

    #define _APS_NEXT_COMMAND_VALUE 40001

    #define _APS_NEXT_CONTROL_VALUE 1013

    #define _APS_NEXT_SYMED_VALUE 101

    #endif

    #endif

    이파일이.. 오류는전부없어졌는데 실행을해도 콘솔창도안나오고.. 빌드는되는데 아무창도 뜨질않네요.. 비주얼스튜디오 2017입니다. 헤더파일도 cpp파일이랑 같은경로에 넣어놨습니다.

    몇번 빌드했더니 이제 빌드했다고 밑에 창에 메시지도안나오고.. 멈추진않앗는데 아무동작을 안하네요 ㅜㅜㅜ

    왜그런건가요