[c++] 네트워크 프로그래밍과 데이터 압축

이 글에서는 C++로 네트워크 프로그래밍과 데이터 압축을 구현하는 방법에 대해 살펴보겠습니다. 먼저 네트워크 프로그래밍을 위해 소켓 프로그래밍을 사용하고, 그리고 데이터 압축을 위해 zlib 라이브러리를 활용할 것입니다.

네트워크 프로그래밍

네트워크 프로그래밍을 위해 C++에서는 소켓을 사용합니다. 소켓은 네트워크 통신을 위한 엔드포인트를 만들어주는 방법으로, TCP 또는 UDP를 이용하여 데이터를 주고 받을 수 있습니다.

아래는 TCP 소켓 서버와 클라이언트의 간단한 예제 코드입니다.

TCP 소켓 서버

#include <iostream>
#include <string>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")

int main() {
    // 소켓 초기화
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    int wsOK = WSAStartup(ver, &wsData);
    if (wsOK != 0) {
        std::cerr << "Can't initialize winsock! Quitting" << std::endl;
        return 0;
    }

    // 소켓 생성
    SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
    if (listening == INVALID_SOCKET) {
        std::cerr << "Can't create a socket! Quitting" << std::endl;
        return 0;
    }

    // 소켓 주소 설정
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(54000);
    hint.sin_addr.S_un.S_addr = INADDR_ANY;

    // 바인딩
    bind(listening, (sockaddr*)&hint, sizeof(hint));

    // 리스닝
    listen(listening, SOMAXCONN);

    // 클라이언트 연결 수락
    sockaddr_in client;
    int clientSize = sizeof(client);
    SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);

    // 클라이언트 소켓에서 데이터 수신 및 전송
    char buf[4096];
    while (true) {
        ZeroMemory(buf, 4096);
        int bytesReceived = recv(clientSocket, buf, 4096, 0);
        if (bytesReceived == SOCKET_ERROR) {
            std::cerr << "Error in recv(). Quitting" << std::endl;
            break;
        }
        if (bytesReceived == 0) {
            std::cout << "Client disconnected." << std::endl;
            break;
        }
        std::cout << std::string(buf, 0, bytesReceived) << std::endl;
    }

    // 소켓 클린업
    closesocket(clientSocket);
    WSACleanup();
}

TCP 소켓 클라이언트

#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")

int main() {
    // 소켓 초기화
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    int wsOK = WSAStartup(ver, &wsData);
    if (wsOK != 0) {
        std::cerr << "Can't initialize winsock! Quitting" << std::endl;
        return 0;
    }

    // 소켓 생성
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        std::cerr << "Can't create a socket! Quitting" << std::endl;
        return 0;
    }

    // 연결
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(54000);
    inet_pton(AF_INET, "127.0.0.1", &hint.sin_addr);
    int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
    if (connResult == SOCKET_ERROR) {
        std::cerr << "Can't connect to server! Quitting" << std::endl;
        return 0;
    }

    // 데이터 전송
    char buf[4096];
    std::string userInput;

    do {
        std::cout << "> ";
        std::getline(std::cin, userInput);

        if (userInput.size() > 0) {
            int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
            if (sendResult != SOCKET_ERROR) {
                ZeroMemory(buf, 4096);
                int bytesReceived = recv(sock, buf, 4096, 0);
                if (bytesReceived > 0) {
                    std::cout << "SERVER> " << std::string(buf, 0, bytesReceived) << std::endl;
                }
            }
        }
    } while (userInput.size() > 0);

    // 소켓 클린업
    closesocket(sock);
    WSACleanup();
}

데이터 압축

데이터 압축을 위해 zlib 라이브러리를 사용할 수 있습니다. zlib은 데이터를 압축하고 해제하는 데 사용되는 라이브러리로, C++에서도 사용할 수 있습니다.

아래는 zlib을 사용하여 데이터를 압축하고 해제하는 간단한 예제 코드입니다.

데이터 압축 및 해제

#include <iostream>
#include <zlib.h>

int main() {
    std::string input = "This is the input data that needs to be compressed and decompressed using zlib library.";
    std::cout << "Input data: " << input << std::endl;

    // 압축
    uLong sourceLen = input.size();
    uLong destLen = compressBound(sourceLen);
    Bytef* dest = new Bytef[destLen];
    compress(dest, &destLen, (const Bytef*)input.c_str(), sourceLen);

    // 해제
    uLong decompressedLen = sourceLen;
    Bytef* decompressed = new Bytef[decompressedLen];
    uncompress(decompressed, &decompressedLen, dest, destLen);

    std::string output = std::string((char*)decompressed);
    std::cout << "Decompressed data: " << output << std::endl;

    delete[] dest;
    delete[] decompressed;
}

위의 코드는 입력 데이터를 zlib을 이용하여 압축하고 다시 해제하는 과정을 보여줍니다.

이상으로 C++를 이용한 네트워크 프로그래밍과 데이터 압축에 대한 내용을 살펴보았습니다. 각각의 주제에 대해 자세한 정보는 각 라이브러리의 공식 문서를 참고하시기 바랍니다.

레퍼런스