25.10.27 개발일지 / C++ MFC 프로젝트 2일차

2025. 11. 13. 18:08·LMS 7/개발일지

회의 내용

패킷 구조 논의

1) JSON만 주고 받기

2) 길이 + JSON

3) 길이 + BinaryHeader + BinaryBdoy

4) BinaryHeader + JSON + BinaryImage

​

> 여러가지 논의가 있었지만 결정된 건 아래 구조임.

Header : MSG(1) + BodyLen(4) + ImgID(4)

Body : IMG or RESULT

로 결정함.


공통 프로토콜(MFC 클라이언트용)

<CommonProtocol.h>

#pragma once
#include <cstdint>

// ======================
// 공통 프로토콜 정의
// ======================

// 메시지 타입(1Byte)
enum class MsgType : uint8_t
{
    IMG_REQ = 1, // 이미지 전송 요청
    IMG_RES = 2, // 이미지 전송 응답
    RESULT_REQ = 3, // 결과 요청
    RESULT_RES = 4, // 결과 응답
    HEARTBEAT = 9  // 연결 유지용
};

// 고정값
constexpr int MAX_JSON_SIZE = 4096;   // 메타 정보 최대 크기
constexpr int MAX_IMAGE_SIZE = 1 * 1024 * 1024; // 최대 1MB 이미지
constexpr int HEADER_SIZE = 9;             // 1 + 4 + 4 = 9바이트

#pragma pack(push, 1)
struct PacketHeader
{
    uint8_t msgType; // 1Byte
    uint32_t bodyLen; // 4Byte
    uint32_t imgId; // 4Byte
};
#pragma pack(pop)

 

<Pakcet.h>

#pragma once // 헤더 중복방지

#include "CommonProtocol.h"
#include <string>
#include <vector>
#include <atomic>

#ifdef _WIN32
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#else // 리눅스용
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR   -1
typedef int SOCKET;
#endif

// ======================
// 패킷 클래스
// ======================
class Packet
{
public:
    Packet();
    ~Packet();

    // 연결
    bool Connect(const std::string& ip, uint16_t port);
    void Disconnect();

    // 송/수신
    bool Send(MsgType type, const std::vector<uint8_t>& body);
    bool Receive(MsgType& outType, uint32_t& outImgId, std::vector<uint8_t>& outBody);

private:
    SOCKET sock; // 소켓
    std::atomic<uint32_t> nextImgId; // 이미지 ID(자동 증가)

    // 송/수신 루프
    bool sendAll(const void* data, size_t size);
    bool recvAll(void* data, size_t size);
};

 

<Packet.cpp>

#include "pch.h"
#include "Packet.h"
#include <iostream>

// 생성자, 소멸자
Packet::Packet() : sock(INVALID_SOCKET), nextImgId(1) {}
Packet::~Packet() { Disconnect(); }

// 연결 메서드
bool Packet::Connect(const std::string& ip, uint16_t port)
{
#ifdef _WIN32 // 윈도우 전용 초기화
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
#endif

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        std::cerr << "[ERROR] 소켓 생성 실패됨\n";
        return false;
    }

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);

    if (connect(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
        std::cerr << "[ERROR] 연결 실패됨\n";
        Disconnect();
        return false;
    }

    std::cout << "[INFO] 연결됨 => " << ip << ":" << port << "\n";
    return true;
}

// 종료 메서드
void Packet::Disconnect()
{
    if (sock != INVALID_SOCKET) {

#ifdef _WIN32
        closesocket(sock);
        WSACleanup();
#else
        close(sock);
#endif

        sock = INVALID_SOCKET;
        std::cout << "[INFO] 연결해제됨\n";
    }
}

// 데이터 수/송신 루프(모든 데이터 받기)
bool Packet::sendAll(const void* data, size_t size)
{
    const char* ptr = reinterpret_cast<const char*>(data);
    size_t total = 0;
    while (total < size)
    {
        int sent = send(sock, ptr + total, static_cast<int>(size - total), 0);
        if (sent <= 0)
            return false;
        total += sent;
    }
    return true;
}
bool Packet::recvAll(void* data, size_t size)
{
    char* ptr = reinterpret_cast<char*>(data);
    size_t total = 0;
    while (total < size)
    {
        int r = recv(sock, ptr + total, static_cast<int>(size - total), 0);
        if (r <= 0)
            return false;
        total += r;
    }
    return true;
}

// 데이터 전송 메서드
bool Packet::Send(MsgType type, const std::vector<uint8_t>& body)
{
    if (sock == INVALID_SOCKET)
        return false;

    PacketHeader header{};
    header.msgType = static_cast<uint8_t>(type);
    header.bodyLen = static_cast<uint32_t>(body.size());
    header.imgId = nextImgId.fetch_add(1); // 자동 1씩 증가

    // ---- Step 1: Header(9Byte)
    if (!sendAll(&header, sizeof(header)))
        return false;

    // ---- Step 2: Body(이미지 or 결과)
    if (header.bodyLen > 0)
        if (!sendAll(body.data(), body.size()))
            return false;

    std::cout << "[SEND] Header: "
        << "MsgType=" << (int)header.msgType
        << ", BodyLen=" << header.bodyLen
        << ", ImgId=" << header.imgId << "\n";
    return true;
}

bool Packet::Receive(MsgType& outType, uint32_t& outImgId, std::vector<uint8_t>& outBody)
{
    outBody.clear();

    // ---- Step 1: Header
    PacketHeader header{};
    if (!recvAll(&header, sizeof(header)))
        return false;
    outType = static_cast<MsgType>(header.msgType);
    outImgId = header.imgId;

    // ---- Step 2: Body
    if (header.bodyLen > 0)
    {
        outBody.resize(header.bodyLen);
        if (!recvAll(outBody.data(), header.bodyLen))
            return false;
    }

    std::cout
        << "[RECV] MsgType=" << (int)header.msgType
        << ", BodyLen=" << header.bodyLen
        << ", ImgId=" << header.imgId << "\n";
    return true;
}

MFC 학습 내용

1. MFC(Microsoft Foundation Class)

> Win32 API 기반

> 메시지 루프 기반 : 이벤트 발생 -> "메시지 맵" -> 함수

> App : 프로그램 전체 관리 / Dialog : 창(UI)​

2. 프로그램 전체 흐름

Windows OS

↓

WinMain()

↓

AfxWinMain() : MFC 내부 진입점

↓

CMFCClientApp::InitInstance()

↓

CMFCClientDlg dlg;

dlg.DoModal(); : 메인 대화상자 실행

↓

대화상자 종료 시 → InitInstance() 반환(FALSE)

↓

프로그램 종료​

3. 주요 클래스

1) CMFCClientApp

> 프로그램 진입점, 초기화 및 종료

> InitInstance() : main() 과 유사함.

> return FALSE; : 대화상자 닫히면 프로그램 종료

2) CMFClientDlg

> 인터페이스(UI) 담당, 창, 버튼/이벤트

> 메시지 맵 : BEGIN_MESSAGE_MAP() ~ END_MESSAGE_MAP() 을 통한 이벤트 -> 함수

4. 메시지 맵

BEGIN_MESSAGE_MAP(CMFCClientDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_CONNECT, &CMFCClientDlg::OnBnClickedBtnConnect)
END_MESSAGE_MAP()

> ON_WM_SYSCOMMAND() : 시스템 메뉴 처리

> ON_WM_PAINT() : 창을 다시 그림

> ON_WM_QUERYDRAGICON() : 최소화 상태에서 아이콘 요청

> ON_BN_CLICKED() : 버튼 클릭 -> 함수 연결

​5. 주요 함수(생성시 기본)

> InitInstance() : 프로그램 시작시 최초 실행

> OnInitDialog() : 창이 처음 표시될 때 한 번만 실행

> OnSysCommand() : 정보(About) 클릭시 About 창 표시

> OnPaint() : 창 다시 그릴 때(최소화/복원)

> OnQueryDragIcon() : 최소화된 창 드래그 시 표시할 아이콘 지정

'LMS 7 > 개발일지' 카테고리의 다른 글

25.10.29 개발일지 / C++ MFC 프로젝트 4일차  (0) 2025.11.14
25.10.28 개발일지 MFC 프로젝트 3일차(Pylon, openCV)  (0) 2025.11.13
25.10.26 개발일지 / Git 병합(pull/merge)  (0) 2025.11.13
25.10.24 개발일지 / MFC 프로젝트 1일차  (0) 2025.11.13
25.10.22 개발일지 / (주)그림  (0) 2025.11.13
'LMS 7/개발일지' 카테고리의 다른 글
  • 25.10.29 개발일지 / C++ MFC 프로젝트 4일차
  • 25.10.28 개발일지 MFC 프로젝트 3일차(Pylon, openCV)
  • 25.10.26 개발일지 / Git 병합(pull/merge)
  • 25.10.24 개발일지 / MFC 프로젝트 1일차
m_Dev
m_Dev
  • m_Dev
    m_Dev
    m_Dev
  • 전체
    오늘
    어제
    • 분류 전체보기
      • MAIN STUDY
        • 정보보안
        • 빅데이터
        • 정보처리
        • 컴퓨터 구조
        • 기타
      • JOB
        • Study
        • Project
      • LMS 7
        • 개발일지
      • FRAMEWORK
        • Qt
        • MFC
        • Winform
        • WPF
        • MAUI
      • NETWORK
        • Study
        • Assignment
      • PYTHON
        • Set
        • Study
        • Assignment
        • Project
      • C
        • Set
        • Study
        • Assignment
        • Project
      • C++
        • Set
        • Study
        • Assignment
        • Project
      • C#
        • Set
        • Study
        • Assignment
        • Project
      • DATABASE
        • MySQL
        • SQLite
      • IDE
        • VisualStudioCode
        • VisualStudio
        • Pycharm
        • Colab
      • 기타
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
m_Dev
25.10.27 개발일지 / C++ MFC 프로젝트 2일차
상단으로

티스토리툴바