<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>GetThePower</title>
    <link>https://azaazaganbare.tistory.com/</link>
    <description>C, C++, MFC, C#, Python, MySQL, JavaScript 등 학습 중.
이 블로그는 학습 내용과 프로젝트를 정리하는 공간입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 21 Jun 2026 20:47:33 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>powergirl</managingEditor>
    <image>
      <title>GetThePower</title>
      <url>https://tistory1.daumcdn.net/tistory/7982623/attach/748847147ef14ae0b2730ccfc45d38d5</url>
      <link>https://azaazaganbare.tistory.com</link>
    </image>
    <item>
      <title>[Win32] IOCP 기반 + 길이 프레임 + Worker Thread 풀</title>
      <link>https://azaazaganbare.tistory.com/138</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;IOCP &lt;br /&gt;+ OVERLAPPED 기반 비동기 recv/send &lt;br /&gt;+ 길이(4byte) + 데이터 프레임 &lt;br /&gt;+ CPU 코어 기반 Worker Thread&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Win32 서버 구조&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766830015339&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;main
 ├─ WSAStartup
 ├─ listen socket 생성
 ├─ IOCP 생성
 ├─ Worker Thread 풀 생성
 ├─ accept loop
 │    ├─ ClientContext 생성
 │    ├─ CreateIoCompletionPort (socket 등록)
 │    └─ 최초 WSARecv 요청
 └─ 종료 처리&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;전체 구조&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766830128401&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MFC Project
 ├─ CMainDlg / CMainFrame (UI)
 ├─ IocpServer.h
 ├─ IocpServer.cpp
 └─ ClientContext.h&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;ClientContext.h&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766830156163&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;mswsock.h&amp;gt;

struct ClientContext
{
    SOCKET socket;
    OVERLAPPED overlapped;
    WSABUF wsaBuf;

    char buffer[4096];

    int recvBytes;
    int expectedBytes;

    ClientContext()
    {
        ZeroMemory(this, sizeof(ClientContext));
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수 Win32 구조체 유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;IocpServer.h&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766830183810&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &quot;ClientContext.h&quot;

class CIocpServer
{
public:
    CIocpServer();
    ~CIocpServer();

    bool Start(int port);
    void Stop();

private:
    static DWORD WINAPI WorkerThread(LPVOID param);

    void AcceptLoop();
    void CloseAllClients();

private:
    SOCKET m_listenSocket;
    HANDLE m_hIOCP;

    std::vector&amp;lt;HANDLE&amp;gt; m_workerThreads;
    bool m_running;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;IocpServer.cpp&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766830218338&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;IocpServer.h&quot;
#include &amp;lt;process.h&amp;gt;

#define IOCP_EXIT_KEY 0xFFFFFFFF

CIocpServer::CIocpServer()
    : m_listenSocket(INVALID_SOCKET),
      m_hIOCP(NULL),
      m_running(false)
{
}

// 서버 시작
bool CIocpServer::Start(int port)
{
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsa);

    m_listenSocket = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    bind(m_listenSocket, (SOCKADDR*)&amp;amp;addr, sizeof(addr));
    listen(m_listenSocket, SOMAXCONN);

    m_hIOCP = CreateIoCompletionPort(
        INVALID_HANDLE_VALUE,
        NULL,
        0,
        0
    );

    SYSTEM_INFO si;
    GetSystemInfo(&amp;amp;si);
    int workerCount = si.dwNumberOfProcessors * 2;

    for (int i = 0; i &amp;lt; workerCount; i++)
    {
        HANDLE hThread = CreateThread(
            NULL,
            0,
            WorkerThread,
            this,
            0,
            NULL
        );

        m_workerThreads.push_back(hThread);
    }

    m_running = true;

    AcceptLoop();
    return true;
}

// accept 루프
void CIocpServer::AcceptLoop()
{
    while (m_running)
    {
        SOCKET client = accept(m_listenSocket, NULL, NULL);
        if (client == INVALID_SOCKET)
            break;

        ClientContext* ctx = new ClientContext;
        ctx-&amp;gt;socket = client;

        ctx-&amp;gt;expectedBytes = sizeof(int);
        ctx-&amp;gt;recvBytes = 0;

        ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
        ctx-&amp;gt;wsaBuf.len = sizeof(int);

        CreateIoCompletionPort(
            (HANDLE)client,
            m_hIOCP,
            (ULONG_PTR)ctx,
            0
        );

        DWORD flags = 0;
        WSARecv(
            client,
            &amp;amp;ctx-&amp;gt;wsaBuf,
            1,
            NULL,
            &amp;amp;flags,
            &amp;amp;ctx-&amp;gt;overlapped,
            NULL
        );
    }
}

// Worker Thread
DWORD WINAPI CIocpServer::WorkerThread(LPVOID param)
{
    CIocpServer* server = (CIocpServer*)param;

    while (true)
    {
        DWORD bytes;
        ULONG_PTR key;
        OVERLAPPED* ov;

        GetQueuedCompletionStatus(
            server-&amp;gt;m_hIOCP,
            &amp;amp;bytes,
            &amp;amp;key,
            &amp;amp;ov,
            INFINITE
        );

        if (key == IOCP_EXIT_KEY)
            break;

        ClientContext* ctx = (ClientContext*)key;

        if (bytes == 0)
        {
            closesocket(ctx-&amp;gt;socket);
            delete ctx;
            continue;
        }

        ctx-&amp;gt;recvBytes += bytes;

        if (ctx-&amp;gt;recvBytes &amp;lt; ctx-&amp;gt;expectedBytes)
        {
            ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer + ctx-&amp;gt;recvBytes;
            ctx-&amp;gt;wsaBuf.len = ctx-&amp;gt;expectedBytes - ctx-&amp;gt;recvBytes;

            WSARecv(ctx-&amp;gt;socket, &amp;amp;ctx-&amp;gt;wsaBuf, 1, NULL, 0, &amp;amp;ctx-&amp;gt;overlapped, NULL);
            continue;
        }

        if (ctx-&amp;gt;expectedBytes == sizeof(int))
        {
            int size;
            memcpy(&amp;amp;size, ctx-&amp;gt;buffer, sizeof(int));
            ctx-&amp;gt;expectedBytes = ntohl(size);
            ctx-&amp;gt;recvBytes = 0;

            ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
            ctx-&amp;gt;wsaBuf.len = ctx-&amp;gt;expectedBytes;

            WSARecv(ctx-&amp;gt;socket, &amp;amp;ctx-&amp;gt;wsaBuf, 1, NULL, 0, &amp;amp;ctx-&amp;gt;overlapped, NULL);
        }
        else
        {
            ctx-&amp;gt;buffer[ctx-&amp;gt;expectedBytes] = '\0';
            // 메시지 처리 지점

            ctx-&amp;gt;expectedBytes = sizeof(int);
            ctx-&amp;gt;recvBytes = 0;

            ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
            ctx-&amp;gt;wsaBuf.len = sizeof(int);

            WSARecv(ctx-&amp;gt;socket, &amp;amp;ctx-&amp;gt;wsaBuf, 1, NULL, 0, &amp;amp;ctx-&amp;gt;overlapped, NULL);
        }
    }

    return 0;
}

// 서버 종료
void CIocpServer::Stop()
{
    m_running = false;
    closesocket(m_listenSocket);

    for (size_t i = 0; i &amp;lt; m_workerThreads.size(); i++)
    {
        PostQueuedCompletionStatus(
            m_hIOCP,
            0,
            IOCP_EXIT_KEY,
            NULL
        );
    }

    WaitForMultipleObjects(
        (DWORD)m_workerThreads.size(),
        m_workerThreads.data(),
        TRUE,
        INFINITE
    );

    CloseHandle(m_hIOCP);
    WSACleanup();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;MFC에서 사용하는 방법&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766830397891&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CIocpServer m_server;

BOOL CMainDlg::OnInitDialog()
{
    m_server.Start(9000);
    return TRUE;
}

void CMainDlg::OnDestroy()
{
    m_server.Stop();
    CDialogEx::OnDestroy();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/138</guid>
      <comments>https://azaazaganbare.tistory.com/138#entry138comment</comments>
      <pubDate>Sat, 27 Dec 2025 19:14:01 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] IOCP Worker Thread 다중화</title>
      <link>https://azaazaganbare.tistory.com/137</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Worker Thread 개수 권장 기준&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829657239&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SYSTEM_INFO si;
GetSystemInfo(&amp;amp;si);

int workerCount = si.dwNumberOfProcessors * 2;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Worker Thread 다중 생성&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829705943&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::vector&amp;lt;HANDLE&amp;gt; g_workerThreads;

for (int i = 0; i &amp;lt; workerCount; i++)
{
    HANDLE hThread = CreateThread(
        NULL,
        0,
        WorkerThread,
        NULL,
        0,
        NULL
    );

    g_workerThreads.push_back(hThread);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;종료용 Completion Packet 전송&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829762503&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; workerCount; i++)
{
    PostQueuedCompletionStatus(
        g_hIOCP,
        0,
        IOCP_EXIT_KEY,
        NULL
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Worker Thread 종료 처리&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829779319&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DWORD WINAPI WorkerThread(LPVOID)
{
    while (true)
    {
        DWORD bytes;
        ULONG_PTR key;
        OVERLAPPED* ov;

        GetQueuedCompletionStatus(
            g_hIOCP,
            &amp;amp;bytes,
            &amp;amp;key,
            &amp;amp;ov,
            INFINITE
        );

        if (key == IOCP_EXIT_KEY)
        {
            break; // 정상 종료
        }

        ClientContext* ctx = (ClientContext*)key;

        if (bytes == 0)
        {
            closesocket(ctx-&amp;gt;socket);
            delete ctx;
            continue;
        }

        // recv 처리...
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/137</guid>
      <comments>https://azaazaganbare.tistory.com/137#entry137comment</comments>
      <pubDate>Sat, 27 Dec 2025 19:05:50 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] IOCP 서버</title>
      <link>https://azaazaganbare.tistory.com/136</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;IOCP 는 Windows 전용 고성능 비동기 I/O 모델로, 정식 명칭은 I/O Completion Port.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;IOCP 객체 (Completion Port)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766821270878&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HANDLE hIOCP = CreateIoCompletionPort(...);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 완료 알림을 넣어두는 큐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완료된 recv/send 결과가 쌓임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;소켓을 IOCP에 등록&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766821393904&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CreateIoCompletionPort(
    (HANDLE)clientSocket,
    hIOCP,
    (ULONG_PTR)clientContext,
    0
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;recv 요청&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766821428367&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WSARecv(sock, &amp;amp;buf, 1, NULL, &amp;amp;flags, &amp;amp;ov, NULL);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;IOCP 서버의 스레드&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766826498768&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (true)
{
    GetQueuedCompletionStatus(
        hIOCP,
        &amp;amp;bytes,
        &amp;amp;key,
        &amp;amp;overlapped,
        INFINITE
    );

    // 여기로 &quot;작업 끝났음&quot;이 들어옴
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOCP 서버 최소 동작 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Clientcontext - 핵심 구조체&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766827026039&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct ClientContext
{
    SOCKET socket;
    OVERLAPPED overlapped;
    WSABUF wsaBuf;
    char buffer[1024];
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;socket : 클라이언트 소켓&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OVERLAPPED : 비동기 작업 식별자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WSABUF : recv 대상 버퍼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;buffer : 실제 데이터 공간&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;전연 IOCP 핸들&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766827103968&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HANDLE g_hIOCP;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Worker Thread&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766827408394&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DWORD WINAPI WorkerThread(LPVOID)
{
    while (true)
    {
        DWORD bytesTransferred;
        ULONG_PTR completionKey;
        OVERLAPPED* pOverlapped;

        BOOL ret = GetQueuedCompletionStatus(
            g_hIOCP,
            &amp;amp;bytesTransferred,
            &amp;amp;completionKey,
            &amp;amp;pOverlapped,
            INFINITE
        );

        ClientContext* ctx = (ClientContext*)completionKey;

        if (bytesTransferred == 0)
        {
            closesocket(ctx-&amp;gt;socket);
            delete ctx;
            continue;
        }

        ctx-&amp;gt;buffer[bytesTransferred] = '\0';
        printf(&quot;Recv: %s\n&quot;, ctx-&amp;gt;buffer);

        // 다시 recv 요청
        ZeroMemory(&amp;amp;ctx-&amp;gt;overlapped, sizeof(OVERLAPPED));

        DWORD flags = 0;
        WSARecv(
            ctx-&amp;gt;socket,
            &amp;amp;ctx-&amp;gt;wsaBuf,
            1,
            NULL,
            &amp;amp;flags,
            &amp;amp;ctx-&amp;gt;overlapped,
            NULL
        );
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서버 초기화 &amp;amp; 메인&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766827502339&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main()
{
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsa);

    SOCKET listenSock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9000);
    addr.sin_addr.s_addr = INADDR_ANY;

    bind(listenSock, (SOCKADDR*)&amp;amp;addr, sizeof(addr));
    listen(listenSock, SOMAXCONN);

    // IOCP 생성
    g_hIOCP = CreateIoCompletionPort(
        INVALID_HANDLE_VALUE,
        NULL,
        0,
        0
    );

    // Worker Thread 1개 (최소)
    CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL);

    printf(&quot;IOCP Server Start\n&quot;);

    while (true)
    {
        SOCKET clientSock = accept(listenSock, NULL, NULL);

        ClientContext* ctx = new ClientContext;
        ZeroMemory(ctx, sizeof(ClientContext));

        ctx-&amp;gt;socket = clientSock;
        ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
        ctx-&amp;gt;wsaBuf.len = sizeof(ctx-&amp;gt;buffer);

        // 소켓을 IOCP에 연결
        CreateIoCompletionPort(
            (HANDLE)clientSock,
            g_hIOCP,
            (ULONG_PTR)ctx,
            0
        );

        // 최초 recv 요청
        DWORD flags = 0;
        WSARecv(
            clientSock,
            &amp;amp;ctx-&amp;gt;wsaBuf,
            1,
            NULL,
            &amp;amp;flags,
            &amp;amp;ctx-&amp;gt;overlapped,
            NULL
        );
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOCP에서 길이 + 데이터 프레임 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;전송 규칙&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[4바이트 길이][데이터 본문]&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;ClientContext 확장&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829441640&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct ClientContext
{
    SOCKET socket;
    OVERLAPPED overlapped;
    WSABUF wsaBuf;

    char buffer[4096];

    int recvBytes;      // 지금까지 받은 바이트
    int expectedBytes;  // 이번에 받아야 할 총 바이트
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOCP에서는 &amp;ldquo;상태&amp;rdquo;를 Context에 저장한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;최초 recv 요청 (길이 4바이트)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829479933&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ctx-&amp;gt;recvBytes = 0;
ctx-&amp;gt;expectedBytes = sizeof(int);

ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
ctx-&amp;gt;wsaBuf.len = ctx-&amp;gt;expectedBytes;

WSARecv(
    ctx-&amp;gt;socket,
    &amp;amp;ctx-&amp;gt;wsaBuf,
    1,
    NULL,
    0,
    &amp;amp;ctx-&amp;gt;overlapped,
    NULL
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;WorkerThread에서 프레임 처리&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829509582&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DWORD WINAPI WorkerThread(LPVOID)
{
    while (true)
    {
        DWORD bytesTransferred;
        ULONG_PTR key;
        OVERLAPPED* ov;

        GetQueuedCompletionStatus(
            g_hIOCP,
            &amp;amp;bytesTransferred,
            &amp;amp;key,
            &amp;amp;ov,
            INFINITE
        );

        ClientContext* ctx = (ClientContext*)key;

        if (bytesTransferred == 0)
        {
            closesocket(ctx-&amp;gt;socket);
            delete ctx;
            continue;
        }

        ctx-&amp;gt;recvBytes += bytesTransferred;

        if (ctx-&amp;gt;recvBytes &amp;lt; ctx-&amp;gt;expectedBytes)
        {
            // 아직 부족 &amp;rarr; 계속 recv
            ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer + ctx-&amp;gt;recvBytes;
            ctx-&amp;gt;wsaBuf.len = ctx-&amp;gt;expectedBytes - ctx-&amp;gt;recvBytes;

            WSARecv(
                ctx-&amp;gt;socket,
                &amp;amp;ctx-&amp;gt;wsaBuf,
                1,
                NULL,
                0,
                &amp;amp;ctx-&amp;gt;overlapped,
                NULL
            );
            continue;
        }

        // 여기 오면 &quot;이번 프레임 완성&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;길이 프레임인지 / 데이터 프레임인지 구분&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766829542461&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        if (ctx-&amp;gt;expectedBytes == sizeof(int))
        {
            int bodySize;
            memcpy(&amp;amp;bodySize, ctx-&amp;gt;buffer, sizeof(int));
            bodySize = ntohl(bodySize);

            ctx-&amp;gt;recvBytes = 0;
            ctx-&amp;gt;expectedBytes = bodySize;

            ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
            ctx-&amp;gt;wsaBuf.len = bodySize;

            WSARecv(
                ctx-&amp;gt;socket,
                &amp;amp;ctx-&amp;gt;wsaBuf,
                1,
                NULL,
                0,
                &amp;amp;ctx-&amp;gt;overlapped,
                NULL
            );
        }
        else
        {
            // 데이터 프레임 완성
            ctx-&amp;gt;buffer[ctx-&amp;gt;expectedBytes] = '\0';
            printf(&quot;Recv Msg: %s\n&quot;, ctx-&amp;gt;buffer);

            // 다시 길이부터 받기
            ctx-&amp;gt;recvBytes = 0;
            ctx-&amp;gt;expectedBytes = sizeof(int);

            ctx-&amp;gt;wsaBuf.buf = ctx-&amp;gt;buffer;
            ctx-&amp;gt;wsaBuf.len = sizeof(int);

            WSARecv(
                ctx-&amp;gt;socket,
                &amp;amp;ctx-&amp;gt;wsaBuf,
                1,
                NULL,
                0,
                &amp;amp;ctx-&amp;gt;overlapped,
                NULL
            );
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/136</guid>
      <comments>https://azaazaganbare.tistory.com/136#entry136comment</comments>
      <pubDate>Sat, 27 Dec 2025 18:59:35 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] select 서버</title>
      <link>https://azaazaganbare.tistory.com/135</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Thread model&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;select model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Thread&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;클라이엉트 수만큼&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;recv&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;블로킹&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;준비된 소켓만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;구조&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;직관적&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;상태 기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;확장성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;낮음&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;중간&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;select 는 recv 를 대신하는 게 아니라, recv 를 호출해도 되는 타이밍을 알려줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;select 서버 전체 흐름&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817295711&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (true)
{
    select(...)
    for (읽기 가능한 소켓)
    {
        if (아직 길이 안 받음)
            recv 길이
        else
            recv 데이터
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;select 서버에 필요한 구조체&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817252607&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct ClientInfo
{
    SOCKET socket;
    int expectedSize;   // 다음에 받아야 할 데이터 크기
    int receivedSize;   // 지금까지 받은 크기
    char buffer[1024];
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;select 준비&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817375383&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fd_set readSet;
FD_ZERO(&amp;amp;readSet);
FD_SET(listenSock, &amp;amp;readSet);

for (auto&amp;amp; c : clients)
{
    FD_SET(c.socket, &amp;amp;readSet);
}

select(0, &amp;amp;readSet, NULL, NULL, NULL);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;새 클라이언트 accept&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817415675&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (FD_ISSET(listenSock, &amp;amp;readSet))
{
    SOCKET clientSock = accept(listenSock, NULL, NULL);

    ClientInfo ci;
    ci.socket = clientSock;
    ci.expectedSize = 0;
    ci.receivedSize = 0;

    clients.push_back(ci);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;길이 수신&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817458128&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (ci.expectedSize == 0)
{
    int ret = recv(
        ci.socket,
        (char*)&amp;amp;ci.expectedSize + ci.receivedSize,
        sizeof(int) - ci.receivedSize,
        0
    );

    if (ret &amp;lt;= 0)
    {
        // 연결 종료 처리
        continue;
    }

    ci.receivedSize += ret;

    if (ci.receivedSize == sizeof(int))
    {
        ci.expectedSize = ntohl(ci.expectedSize);
        ci.receivedSize = 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;데이터 수신&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817485601&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;else
{
    int ret = recv(
        ci.socket,
        ci.buffer + ci.receivedSize,
        ci.expectedSize - ci.receivedSize,
        0
    );

    if (ret &amp;lt;= 0)
    {
        // 연결 종료 처리
        continue;
    }

    ci.receivedSize += ret;

    if (ci.receivedSize == ci.expectedSize)
    {
        ci.buffer[ci.expectedSize] = '\0';
        std::cout &amp;lt;&amp;lt; &quot;메시지: &quot; &amp;lt;&amp;lt; ci.buffer &amp;lt;&amp;lt; std::endl;

        // 상태 초기화
        ci.expectedSize = 0;
        ci.receivedSize = 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서버&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766817525513&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;ws2tcpip.h&amp;gt;
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

#pragma comment(lib, &quot;ws2_32.lib&quot;)

#define SERVER_PORT 9000
#define MAX_BUF 1024

// ================================
// 클라이언트 상태 구조체
// ================================
struct ClientInfo
{
    SOCKET socket;

    int expectedSize;     // 다음에 받아야 할 데이터 크기
    int receivedSize;     // 현재까지 받은 크기

    char buffer[MAX_BUF];
};

int main()
{
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsa);

    SOCKET listenSock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(SERVER_PORT);

    bind(listenSock, (SOCKADDR*)&amp;amp;serverAddr, sizeof(serverAddr));
    listen(listenSock, SOMAXCONN);

    std::cout &amp;lt;&amp;lt; &quot;select 서버 시작 (Port: &quot; &amp;lt;&amp;lt; SERVER_PORT &amp;lt;&amp;lt; &quot;)\n&quot;;

    std::vector&amp;lt;ClientInfo&amp;gt; clients;

    while (true)
    {
        fd_set readSet;
        FD_ZERO(&amp;amp;readSet);

        FD_SET(listenSock, &amp;amp;readSet);
        SOCKET maxSock = listenSock;

        for (auto&amp;amp; c : clients)
        {
            FD_SET(c.socket, &amp;amp;readSet);
            if (c.socket &amp;gt; maxSock)
                maxSock = c.socket;
        }

        int ret = select(0, &amp;amp;readSet, NULL, NULL, NULL);
        if (ret &amp;lt;= 0)
            continue;

        // ================================
        // 새 클라이언트 접속
        // ================================
        if (FD_ISSET(listenSock, &amp;amp;readSet))
        {
            SOCKET clientSock = accept(listenSock, NULL, NULL);

            ClientInfo ci;
            ci.socket = clientSock;
            ci.expectedSize = 0;
            ci.receivedSize = 0;

            clients.push_back(ci);

            std::cout &amp;lt;&amp;lt; &quot;[접속] socket=&quot; &amp;lt;&amp;lt; clientSock &amp;lt;&amp;lt; &quot;\n&quot;;
        }

        // ================================
        // 클라이언트 데이터 처리
        // ================================
        for (int i = 0; i &amp;lt; clients.size(); )
        {
            ClientInfo&amp;amp; ci = clients[i];

            if (!FD_ISSET(ci.socket, &amp;amp;readSet))
            {
                ++i;
                continue;
            }

            // ----------------------------
            // 1️⃣ 길이 수신 단계
            // ----------------------------
            if (ci.expectedSize == 0)
            {
                int ret = recv(
                    ci.socket,
                    ((char*)&amp;amp;ci.expectedSize) + ci.receivedSize,
                    sizeof(int) - ci.receivedSize,
                    0
                );

                if (ret &amp;lt;= 0)
                {
                    std::cout &amp;lt;&amp;lt; &quot;[종료] socket=&quot; &amp;lt;&amp;lt; ci.socket &amp;lt;&amp;lt; &quot;\n&quot;;
                    closesocket(ci.socket);
                    clients.erase(clients.begin() + i);
                    continue;
                }

                ci.receivedSize += ret;

                if (ci.receivedSize == sizeof(int))
                {
                    ci.expectedSize = ntohl(ci.expectedSize);

                    // 방어 코드
                    if (ci.expectedSize &amp;lt;= 0 || ci.expectedSize &amp;gt; MAX_BUF)
                    {
                        closesocket(ci.socket);
                        clients.erase(clients.begin() + i);
                        continue;
                    }

                    ci.receivedSize = 0;
                }
            }
            // ----------------------------
            // 2️⃣ 데이터 수신 단계
            // ----------------------------
            else
            {
                int ret = recv(
                    ci.socket,
                    ci.buffer + ci.receivedSize,
                    ci.expectedSize - ci.receivedSize,
                    0
                );

                if (ret &amp;lt;= 0)
                {
                    std::cout &amp;lt;&amp;lt; &quot;[종료] socket=&quot; &amp;lt;&amp;lt; ci.socket &amp;lt;&amp;lt; &quot;\n&quot;;
                    closesocket(ci.socket);
                    clients.erase(clients.begin() + i);
                    continue;
                }

                ci.receivedSize += ret;

                if (ci.receivedSize == ci.expectedSize)
                {
                    ci.buffer[ci.expectedSize] = '\0';

                    std::cout &amp;lt;&amp;lt; &quot;[메시지] &quot;
                              &amp;lt;&amp;lt; ci.buffer &amp;lt;&amp;lt; &quot;\n&quot;;

                    // 상태 초기화
                    ci.expectedSize = 0;
                    ci.receivedSize = 0;
                }
            }

            ++i;
        }
    }

    closesocket(listenSock);
    WSACleanup();
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/135</guid>
      <comments>https://azaazaganbare.tistory.com/135#entry135comment</comments>
      <pubDate>Sat, 27 Dec 2025 15:40:17 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] 네트워크 메시지 경계 처리 - Length Prefix</title>
      <link>https://azaazaganbare.tistory.com/134</link>
      <description>&lt;pre id=&quot;code_1766814850850&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[4바이트 길이][실제 데이터]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;recvAll&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766814877977&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int recvAll(SOCKET sock, char* buf, int totalSize)
{
    int received = 0;

    while (received &amp;lt; totalSize)
    {
        int ret = recv(
            sock,
            buf + received,
            totalSize - received,
            0
        );

        if (ret &amp;lt;= 0)
        {
            return -1; // 연결 종료 or 오류
        }

        received += ret;
    }

    return received;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766815425332&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;recv(
    sock,                  // 어느 소켓에서
    buf + received,        // 버퍼의 &quot;다음 빈 자리&quot;
    totalSize - received,  // 아직 필요한 양
    0
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;recv 시나리오&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;100바이트 요청 &amp;gt;&amp;gt; 실제로는 40바이트만 옴&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;recv #1 &amp;gt;&amp;gt; 40바이트 &lt;br /&gt;recv #2 &amp;gt;&amp;gt; 60바이트&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 누적 수신이 필요함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;buf + received&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766815619126&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;buf 시작 주소
&amp;darr;
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]  &amp;larr; totalSize 만큼&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;첫 번째 recv&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766815640342&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;received = 0;

recv(sock, buf + 0, totalSize - 0, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과&lt;/p&gt;
&lt;pre id=&quot;code_1766815650550&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[ A ][ B ][ C ][ D ][ ][ ][ ][ ][ ][ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;buf[0]부터 채움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;두 번째 recv&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766815710183&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;received = 4;

recv(sock, buf + 4, totalSize - 4, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과&lt;/p&gt;
&lt;pre id=&quot;code_1766815736318&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[ A ][ B ][ C ][ D ][ E ][ F ][ G ][ H ][ ][ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약,&lt;/p&gt;
&lt;pre id=&quot;code_1766815797598&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;received = 4;

recv(sock, buf, totalSize, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이랬으면&lt;/p&gt;
&lt;pre id=&quot;code_1766815809951&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[ E ][ F ][ G ][ H ][ ][ ][ ][ ][ ][ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 데이터를 덮어썼을 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/134</guid>
      <comments>https://azaazaganbare.tistory.com/134#entry134comment</comments>
      <pubDate>Sat, 27 Dec 2025 15:12:07 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] 서버 확장 : Thread 도입</title>
      <link>https://azaazaganbare.tistory.com/133</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서버 스레드 설계&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;main thread &amp;gt;&amp;gt; listen / accept&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;client thread &amp;gt;&amp;gt; recv / send / disconnect&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;스레드 함수&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766811122205&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DWORD WINAPI ClientThread(LPVOID lpParam)
{
    ClientInfo* info = (ClientInfo*)lpParam;
    SOCKET clientSocket = info-&amp;gt;socket;
    SOCKADDR_IN clientAddr = info-&amp;gt;addr;

    printf(&quot;클라이언트 처리 시작: %s:%d\n&quot;,
        inet_ntoa(clientAddr.sin_addr),
        ntohs(clientAddr.sin_port));

    int timeout = 5000;
    setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO,
        (char*)&amp;amp;timeout, sizeof(timeout));

    while (true)
    {
        int value = 0;
        int ret = recv(clientSocket, (char*)&amp;amp;value, sizeof(int), 0);

        if (ret &amp;gt; 0)
        {
            printf(&quot;[%s] %d 수신\n&quot;,
                inet_ntoa(clientAddr.sin_addr), value);
        }
        else if (ret == 0)
        {
            printf(&quot;[%s] 정상 종료\n&quot;,
                inet_ntoa(clientAddr.sin_addr));
            break;
        }
        else
        {
            int err = WSAGetLastError();
            if (err == WSAETIMEDOUT)
            {
                continue;
            }
            else
            {
                printf(&quot;[%s] recv 에러: %d\n&quot;,
                    inet_ntoa(clientAddr.sin_addr), err);
                break;
            }
        }
    }

    closesocket(clientSocket);
    delete info;

    printf(&quot;클라이언트 스레드 종료\n&quot;);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;메인 서버 코드 (accept + 스레드 생성)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766812038610&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (true)
{
    SOCKADDR_IN clientAddr = {};
    int addrSize = sizeof(clientAddr);

    SOCKET clientSocket =
        accept(listenSocket, (SOCKADDR*)&amp;amp;clientAddr, &amp;amp;addrSize);

    ClientInfo* info = new ClientInfo;
    info-&amp;gt;socket = clientSocket;
    info-&amp;gt;addr = clientAddr;

    HANDLE hThread = CreateThread(
        nullptr,
        0,
        ClientThread,
        info,
        0,
        nullptr
    );

    CloseHandle(hThread); // 핸들 누수 방지
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;구조체로 전달&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766812050281&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct ClientInfo
{
    SOCKET socket;
    SOCKADDR_IN addr;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서버&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766812193483&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;ws2tcpip.h&amp;gt;
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;process.h&amp;gt;
#include &amp;lt;iostream&amp;gt;

#pragma comment(lib, &quot;ws2_32.lib&quot;)

#define SERVER_PORT 9000
#define BUF_SIZE 1024

// ================================
// 클라이언트 정보 구조체 (실무 정석)
// ================================
struct ClientInfo
{
    SOCKET socket;
    SOCKADDR_IN addr;
};

// ================================
// 클라이언트 처리 스레드
// ================================
unsigned int __stdcall ClientThread(void* arg)
{
    ClientInfo* pClient = (ClientInfo*)arg;

    SOCKET clientSock = pClient-&amp;gt;socket;
    SOCKADDR_IN clientAddr = pClient-&amp;gt;addr;

    char ip[32];
    inet_ntop(AF_INET, &amp;amp;clientAddr.sin_addr, ip, sizeof(ip));

    std::cout &amp;lt;&amp;lt; &quot;[접속] IP: &quot; &amp;lt;&amp;lt; ip
              &amp;lt;&amp;lt; &quot; PORT: &quot; &amp;lt;&amp;lt; ntohs(clientAddr.sin_port) &amp;lt;&amp;lt; std::endl;

    char buf[BUF_SIZE];

    while (true)
    {
        int recvBytes = recv(clientSock, buf, BUF_SIZE, 0);

        if (recvBytes &amp;lt;= 0)
        {
            std::cout &amp;lt;&amp;lt; &quot;[종료] IP: &quot; &amp;lt;&amp;lt; ip &amp;lt;&amp;lt; std::endl;
            break;
        }

        // 받은 데이터 출력
        std::cout &amp;lt;&amp;lt; &quot;[수신] (&quot; &amp;lt;&amp;lt; ip &amp;lt;&amp;lt; &quot;) &quot;
                  &amp;lt;&amp;lt; std::string(buf, recvBytes) &amp;lt;&amp;lt; std::endl;
    }

    closesocket(clientSock);
    delete pClient;   // ⭐ 반드시 힙 해제

    return 0;
}

// ================================
// main
// ================================
int main()
{
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsa);

    SOCKET listenSock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(SERVER_PORT);

    bind(listenSock, (SOCKADDR*)&amp;amp;serverAddr, sizeof(serverAddr));
    listen(listenSock, SOMAXCONN);

    std::cout &amp;lt;&amp;lt; &quot;서버 시작 (Port: &quot; &amp;lt;&amp;lt; SERVER_PORT &amp;lt;&amp;lt; &quot;)&quot; &amp;lt;&amp;lt; std::endl;

    while (true)
    {
        SOCKADDR_IN clientAddr;
        int addrLen = sizeof(clientAddr);

        SOCKET clientSock = accept(
            listenSock,
            (SOCKADDR*)&amp;amp;clientAddr,
            &amp;amp;addrLen
        );

        if (clientSock == INVALID_SOCKET)
        {
            continue;
        }

        // ================================
        // 클라이언트 정보 힙 할당
        // ================================
        ClientInfo* pClient = new ClientInfo;
        pClient-&amp;gt;socket = clientSock;
        pClient-&amp;gt;addr = clientAddr;

        _beginthreadex(
            NULL,
            0,
            ClientThread,
            pClient,
            0,
            NULL
        );
    }

    closesocket(listenSock);
    WSACleanup();
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/133</guid>
      <comments>https://azaazaganbare.tistory.com/133#entry133comment</comments>
      <pubDate>Sat, 27 Dec 2025 14:20:00 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] Windows Socket 기초 - recv 무한 대기 방지</title>
      <link>https://azaazaganbare.tistory.com/132</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;recv 타임아웃&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;setsockopt + SO_RCVTIMEO&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766810257361&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int timeout = 5000; // 5초
setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&amp;amp;timeout, sizeof(timeout));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5초동안 데이터 안 오면 recv() 실패 / 반환값 : SOCKET_ERROR&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WSAGetLstError() &amp;gt;&amp;gt; WSAETIMEDOUT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클라이언트 정보 출력&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766810406577&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inet_ntoa(clientAddr.sin_addr);
ntohs(clientAddr.sin_port);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;recv 반환값&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766810508569&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int ret = recv(clientSocket, (char*)&amp;amp;value, sizeof(int), 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ret &amp;gt; 0 : 받은 바이트 수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ret == 0 : 상대방 정상 종료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ret &amp;lt; 0 : 오류&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서버&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766810421633&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SB003_Server.cpp
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;

#pragma comment(lib, &quot;ws2_32.lib&quot;)

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsaData);

    SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN serverAddr = {};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(9000);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(listenSocket, (SOCKADDR*)&amp;amp;serverAddr, sizeof(serverAddr));
    listen(listenSocket, SOMAXCONN);

    printf(&quot;서버 시작\n&quot;);

    while (true)
    {
        SOCKADDR_IN clientAddr = {};
        int addrSize = sizeof(clientAddr);
        SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&amp;amp;clientAddr, &amp;amp;addrSize);

        printf(&quot;접속: %s:%d\n&quot;,
               inet_ntoa(clientAddr.sin_addr),
               ntohs(clientAddr.sin_port));

        int timeout = 5000;
        setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO,
                   (char*)&amp;amp;timeout, sizeof(timeout));

        while (true)
        {
            int value = 0;
            int ret = recv(clientSocket, (char*)&amp;amp;value, sizeof(int), 0);

            if (ret &amp;gt; 0)
            {
                printf(&quot;수신 값: %d\n&quot;, value);
            }
            else if (ret == 0)
            {
                printf(&quot;클라이언트 연결 종료\n&quot;);
                break;
            }
            else
            {
                int err = WSAGetLastError();
                if (err == WSAETIMEDOUT)
                {
                    printf(&quot;수신 타임아웃\n&quot;);
                    continue;
                }
                else
                {
                    printf(&quot;recv 에러: %d\n&quot;, err);
                    break;
                }
            }
        }

        closesocket(clientSocket);
        printf(&quot;클라이언트 소켓 닫힘\n&quot;);
    }

    closesocket(listenSocket);
    WSACleanup();
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/132</guid>
      <comments>https://azaazaganbare.tistory.com/132#entry132comment</comments>
      <pubDate>Sat, 27 Dec 2025 13:45:26 +0900</pubDate>
    </item>
    <item>
      <title>[Win32] Windows Socket 기초 - TCP 연습</title>
      <link>https://azaazaganbare.tistory.com/131</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. WinSock 초기화&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808462797&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WSAStartup(MAKEWORD(2, 2), &amp;amp;wsaData);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows 는 소켓을 라이브러리로 제공함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;2. 서버 소켓 생성&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808531935&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AF_INET &amp;gt;&amp;gt; IPv4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SOCK_STREAM &amp;gt;&amp;gt; TCP&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;3. 서버 주소 설정&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808602574&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;serverAddr.sin_port = htons(9000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;htons &amp;gt;&amp;gt; Host TO Network Short&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크는 Big Endian&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;4. bind / listen&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808665295&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bind(listenSocket, (SOCKADDR*)&amp;amp;serverAddr, sizeof(serverAddr));
listen(listenSocket, SOMAXCONN);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;5. accept&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808723102&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&amp;amp;clientAddr, &amp;amp;addrSize);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 접속 전까지 무한 대기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;accept 는 TCP 연결 요청이 들어올 때까지 커널 레벨에서 대기 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로킹 함수.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;recv&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808799095&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;recv(clientSocket, (char*)&amp;amp;value, sizeof(int), 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recv 는 수신 버퍼에 데이터가 도착하는 순간 풀림&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recv 가 풀리는 조건&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 커널 수신 버퍼에 데이터가 1바이트라도 도착&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 상대방이 연결을 종료 (FIN 수신)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 에러 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sizeof(int)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 는 데이터 타입을 모름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 바이트를 읽어야 할지 서버가 알 방법이 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;4바이트 정수&quot; 라는 명시적 약속&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서버&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808900808&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SB002_Server.cpp
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;

#pragma comment(lib, &quot;ws2_32.lib&quot;)

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsaData);

    SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN serverAddr = {};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(9000);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(listenSocket, (SOCKADDR*)&amp;amp;serverAddr, sizeof(serverAddr));
    listen(listenSocket, SOMAXCONN);

    printf(&quot;서버 시작\n&quot;);

    while (true)
    {
        printf(&quot;클라이언트 접속 대기...\n&quot;);

        SOCKADDR_IN clientAddr = {};
        int addrSize = sizeof(clientAddr);
        SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&amp;amp;clientAddr, &amp;amp;addrSize);

        printf(&quot;클라이언트 접속됨\n&quot;);

        int value = 0;
        recv(clientSocket, (char*)&amp;amp;value, sizeof(int), 0);

        printf(&quot;수신 값: %d\n&quot;, value);

        closesocket(clientSocket);
    }

    closesocket(listenSocket);
    WSACleanup();
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클라&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766808934720&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SB001_Client.cpp
#include &amp;lt;winsock2.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;

#pragma comment(lib, &quot;ws2_32.lib&quot;)

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &amp;amp;wsaData);

    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN serverAddr = {};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(9000);
    serverAddr.sin_addr.s_addr = inet_addr(&quot;127.0.0.1&quot;);

    connect(sock, (SOCKADDR*)&amp;amp;serverAddr, sizeof(serverAddr));

    int value = 1234;
    send(sock, (char*)&amp;amp;value, sizeof(int), 0);

    closesocket(sock);
    WSACleanup();

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/Win32</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/131</guid>
      <comments>https://azaazaganbare.tistory.com/131#entry131comment</comments>
      <pubDate>Sat, 27 Dec 2025 13:29:43 +0900</pubDate>
    </item>
    <item>
      <title>[MFC] ListBox</title>
      <link>https://azaazaganbare.tistory.com/130</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;도구상자에서 List Box 추가&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPMCQQ/dJMb99LKEQw/Z78chth8AU3aj9POP2gil0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPMCQQ/dJMb99LKEQw/Z78chth8AU3aj9POP2gil0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPMCQQ/dJMb99LKEQw/Z78chth8AU3aj9POP2gil0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPMCQQ%2FdJMb99LKEQw%2FZ78chth8AU3aj9POP2gil0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;791&quot; height=&quot;471&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;List Box 에서 오른쪽 버튼 클릭 후 변수 추가&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9Jsm1/dJMcaiu7zFi/fa8xoDLNj1kTeY5QOk5Ia1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9Jsm1/dJMcaiu7zFi/fa8xoDLNj1kTeY5QOk5Ia1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9Jsm1/dJMcaiu7zFi/fa8xoDLNj1kTeY5QOk5Ia1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9Jsm1%2FdJMcaiu7zFi%2Ffa8xoDLNj1kTeY5QOk5Ia1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;490&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIKnrw/dJMcagxlgWx/T2p2bzWawDOUysEqQjhrHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIKnrw/dJMcagxlgWx/T2p2bzWawDOUysEqQjhrHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIKnrw/dJMcagxlgWx/T2p2bzWawDOUysEqQjhrHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIKnrw%2FdJMcagxlgWx%2FT2p2bzWawDOUysEqQjhrHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;732&quot; height=&quot;528&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;.h&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pk91a/dJMcafrFJEo/6QDGhoWQBglfJ2O6rxmrok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pk91a/dJMcafrFJEo/6QDGhoWQBglfJ2O6rxmrok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pk91a/dJMcafrFJEo/6QDGhoWQBglfJ2O6rxmrok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpk91a%2FdJMcafrFJEo%2F6QDGhoWQBglfJ2O6rxmrok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;354&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;.cpp&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mB450/dJMcac2J3Eq/XTKy3goOjRKQwCTQKYyKk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mB450/dJMcac2J3Eq/XTKy3goOjRKQwCTQKYyKk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mB450/dJMcac2J3Eq/XTKy3goOjRKQwCTQKYyKk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmB450%2FdJMcac2J3Eq%2FXTKy3goOjRKQwCTQKYyKk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;486&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;응용예제 - 로그출력 화면처럼 표현&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766548035892&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CDUMMYDlg::OnBnClickedButton1()
{
	// 에딧에 입력한거
	CString msg;
	GetDlgItemText(IDC_EDIT2, msg);

	int index = m_listBox.InsertString(-1, msg);

	m_listBox.SetCurSel(index);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AYj6K/dJMcahXldxt/Ra3v5ZyzwAnNNUWRP1KPPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AYj6K/dJMcahXldxt/Ra3v5ZyzwAnNNUWRP1KPPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AYj6K/dJMcahXldxt/Ra3v5ZyzwAnNNUWRP1KPPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAYj6K%2FdJMcahXldxt%2FRa3v5ZyzwAnNNUWRP1KPPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;561&quot; height=&quot;315&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;현재 선택된 인덱&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615724550&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int index = m_listBox.GetCurSel();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;아이템 추가 - AddString();&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615622519&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;m_listBox.AddString(L&quot;Apple&quot;);
m_listBox.AddString(L&quot;Banana&quot;);
m_listBox.AddString(L&quot;Orange&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;전체 삭제 - ResetContent()&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615673878&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;m_listBox.ResetContent();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;아이템 개수 - GetCount()&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615692718&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int count = m_listBox.GetCount();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;선택된 문자열 가져오기 - GetText&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615806887&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CString text;
int index = m_listBox.GetCurSel();

if (index != LB_ERR)
{
    m_listBox.GetText(index, text);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;특정 인덱스 삭제&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615858759&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;m_listBox.DeleteString(index);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;특정 위치에 삽&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766615893335&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;m_listBox.InsertString(1, L&quot;Inserted Item&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝에 저장하려면 첫번째 매개변수 0으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;더블클릭시에 해당 인덱스 팝업&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAOl02/dJMcagKSUOk/i6za30MU3m9AyAF9nbMfsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAOl02/dJMcagKSUOk/i6za30MU3m9AyAF9nbMfsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAOl02/dJMcagKSUOk/i6za30MU3m9AyAF9nbMfsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAOl02%2FdJMcagKSUOk%2Fi6za30MU3m9AyAF9nbMfsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;719&quot; height=&quot;546&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caLihl/dJMcabivTgS/AdiewwazKdCrxxxu3Em8j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caLihl/dJMcabivTgS/AdiewwazKdCrxxxu3Em8j0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caLihl/dJMcabivTgS/AdiewwazKdCrxxxu3Em8j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaLihl%2FdJMcabivTgS%2FAdiewwazKdCrxxxu3Em8j0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;380&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766616329155&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CMyDlg::OnLbnDblclkList1()
{
    int index = m_listBox.GetCurSel();

    if (index != LB_ERR)
    {
        CString text;
        m_listBox.GetText(index, text);

        AfxMessageBox(text);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIddRh/dJMcagjN6Hk/eYtY04sZmhCy4J0k5myFo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIddRh/dJMcagjN6Hk/eYtY04sZmhCy4J0k5myFo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIddRh/dJMcagjN6Hk/eYtY04sZmhCy4J0k5myFo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIddRh%2FdJMcagjN6Hk%2FeYtY04sZmhCy4J0k5myFo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;306&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>C++/MFC</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/130</guid>
      <comments>https://azaazaganbare.tistory.com/130#entry130comment</comments>
      <pubDate>Thu, 25 Dec 2025 07:45:48 +0900</pubDate>
    </item>
    <item>
      <title>[MFC] Dialog 추가하기 - DoModal</title>
      <link>https://azaazaganbare.tistory.com/129</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;화면 생성&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스뷰 &amp;gt;&amp;gt; 프로젝트 솔루션 &amp;gt;&amp;gt; Dialog 오른쪽 버튼 &amp;gt;&amp;gt; 삽입&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOpOyo/dJMcaionDFU/G0RGIVKdNYJRZTZApAPgkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOpOyo/dJMcaionDFU/G0RGIVKdNYJRZTZApAPgkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOpOyo/dJMcaionDFU/G0RGIVKdNYJRZTZApAPgkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOpOyo%2FdJMcaionDFU%2FG0RGIVKdNYJRZTZApAPgkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;376&quot; height=&quot;418&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클래스 생성&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 대화상자 사용하기 위해서 클래스 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대화상자 더블클릭하면 클래스 추가하는 창이 뜸&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctRNr6/dJMcacV0xOe/asIl9Zf8GRWH5n24115bTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctRNr6/dJMcacV0xOe/asIl9Zf8GRWH5n24115bTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctRNr6/dJMcacV0xOe/asIl9Zf8GRWH5n24115bTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctRNr6%2FdJMcacV0xOe%2FasIl9Zf8GRWH5n24115bTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1135&quot; height=&quot;721&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;721&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;정형 Dialog (새로운 대화상자 활성화 시 기존 대화상자로 못 감)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1097&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kzei9/dJMcad1DvBd/iEYW0msKCXSx6XHKpwlFoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kzei9/dJMcad1DvBd/iEYW0msKCXSx6XHKpwlFoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kzei9/dJMcad1DvBd/iEYW0msKCXSx6XHKpwlFoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKzei9%2FdJMcad1DvBd%2FiEYW0msKCXSx6XHKpwlFoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1097&quot; height=&quot;540&quot; data-origin-width=&quot;1097&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;대화상자 열기 - DoModal()&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766556644184&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;PopUp.h&quot;;

void CDUMMYDlg::OnBnClickedPopupOpenBtn()
{
	PopUp popup;

	popup.DoModal();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GxhBx/dJMcagjN3wx/3JNS7pHCmf7tV5QPjYyvLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GxhBx/dJMcagjN3wx/3JNS7pHCmf7tV5QPjYyvLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GxhBx/dJMcagjN3wx/3JNS7pHCmf7tV5QPjYyvLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGxhBx%2FdJMcagjN3wx%2F3JNS7pHCmf7tV5QPjYyvLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;388&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;값을 양쪽으로 전달하기&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;값 전달하기 위해서는 저장할 공간 필요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; 결국 값을 가지고 있을곳은 팝업창의 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;PopUp.h&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q79O2/dJMcacaDTDE/V1bWvvCZlfBuZIA31ssk41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q79O2/dJMcacaDTDE/V1bWvvCZlfBuZIA31ssk41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q79O2/dJMcacaDTDE/V1bWvvCZlfBuZIA31ssk41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq79O2%2FdJMcacaDTDE%2FV1bWvvCZlfBuZIA31ssk41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;597&quot; height=&quot;653&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;MainDlg.cpp&lt;/blockquote&gt;
&lt;pre id=&quot;code_1766557695615&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;PopUp.h&quot;;

void CDUMMYDlg::OnBnClickedPopupOpenBtn()
{
	int num = GetDlgItemInt(IDC_EDIT1);
    
	PopUp popup;
	popup.SetNum(num);
	popup.DoModal();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;PopUp 클래스에 init 이 없어서 추가&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D9D9O/dJMcafkT1MZ/Pe0min2wHQJryerJEQkx10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D9D9O/dJMcafkT1MZ/Pe0min2wHQJryerJEQkx10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D9D9O/dJMcafkT1MZ/Pe0min2wHQJryerJEQkx10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD9D9O%2FdJMcafkT1MZ%2FPe0min2wHQJryerJEQkx10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;814&quot; height=&quot;693&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766557724693&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// PopUp 메시지 처리기

BOOL PopUp::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	// TODO:  여기에 추가 초기화 작업을 추가합니다.

	SetDlgItemInt(IDC_EDIT1, num);

	return TRUE;  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAN7f6/dJMcafFdf2e/iMxYdByCpOdyTnYLKTVSK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAN7f6/dJMcafFdf2e/iMxYdByCpOdyTnYLKTVSK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAN7f6/dJMcafFdf2e/iMxYdByCpOdyTnYLKTVSK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAN7f6%2FdJMcafFdf2e%2FiMxYdByCpOdyTnYLKTVSK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;381&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;추가 - 팝업창에서 확인 버튼 누르면 기존 창의 Edit Control 0으로&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w5AqM/dJMcahXlamI/7uSfav8WunTvXkY1xdC1l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w5AqM/dJMcahXlamI/7uSfav8WunTvXkY1xdC1l1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w5AqM/dJMcahXlamI/7uSfav8WunTvXkY1xdC1l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw5AqM%2FdJMcahXlamI%2F7uSfav8WunTvXkY1xdC1l1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;574&quot; height=&quot;225&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++/MFC</category>
      <author>powergirl</author>
      <guid isPermaLink="true">https://azaazaganbare.tistory.com/129</guid>
      <comments>https://azaazaganbare.tistory.com/129#entry129comment</comments>
      <pubDate>Thu, 25 Dec 2025 04:41:37 +0900</pubDate>
    </item>
  </channel>
</rss>