[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++를 이용한 네트워크 프로그래밍과 데이터 압축에 대한 내용을 살펴보았습니다. 각각의 주제에 대해 자세한 정보는 각 라이브러리의 공식 문서를 참고하시기 바랍니다.
레퍼런스
- Microsoft Docs - Winsock https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-start-page
- zlib Home https://zlib.net/