| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- c++ multi chatting room
- placement new
- virtual function table
- std::ostream
- new&delete
- vector size
- delete function
- diamond inheritance
- this call
- increment operator
- virtual destructor
- member function pointer
- dynamic_cast
- operator overloading
- std::endl
- discord bot
- virtual inheritance
- std::vector
- pointer to member data
- C++
- c++ basic practice
- std::cout
- virtual function
- base from member
- constructor
- return by reference
- conversion constructor
- vector capacity
- suffix return type
- 더 지니어스 양면포커
- Today
- Total
I'm FanJae.
[Socket] Byte order에 따른 소켓 통신 시 유의할 점 본문
1. 바이트 저장 순서 (Byte Order)
- 컴퓨터는 데이터를 메모리에 저장할 때 바이트(Byte) 단위로 나눠 저장한다.
- 여러 바이트로 구성된 데이터 타입은 인접한 메모리 주소에 연속적으로 저장된다.
- 이때,여러 바이트로 구성된 데이터를 메모리에 어떤 순서로 저장할지 정하는 방식을 엔디안(Endian)이라고 한다.
2. 엔디안(Endian)
- 앞서 설명한 바와 같이 Endian은 데이터가 메모리에 저장되는 순서를 의미한다.
- Endian은 CPU의 아키텍처의 데이터 저장 방식 설계에 따라 결정된다. 일반적으로, 리틀 앤디안(Little Endian)과 빅 앤디안(Big Endian)의 두가지 방식이 존재한다.
2-1. 빅 엔디안(Big Endian) 방식

- 빅 엔디안 방식은 가장 상위 바이트를 메모리의 가장 낮은 주소에 저장하는 방식이다.
- 바이트 순서를 사람이 숫자를 읽는 방식(왼쪽->오른쪽)과 일치하게 정렬하는 특징이 있으며, 0x0A0B0C0D를 저장하는 경우, 가장 앞 주소에 0x0A가 저장된다.
2-2. 리틀 엔디안(Little Endian) 방식

- Little Endian 방식은 가장 하위 바이트를 메모리의 가장 낮은 주소에 저장하는 방식이다.
- 0x0A0B0C0D를 저장하는 경우, 가장 앞 주소에 0x0D가 저장된다.
이처럼, CPU의 아키텍처에 따라서 메모리에 어떤 순서로 저장하는지 달라진다. 이에 따라서 서로 다른 시스템 간 소켓 통신을 진행 할 때 유의할 점이 존재한다. 예를들어, Little Endian 기반의 x86 서버가 Big Endian 방식의 네트워크 장비와 통신할 경우, 패킷 데이터가 엉뚱하게 해석될 수 있으므로 바이트 오더 변환이 필수적이다.
3. Host Byte Order(호스트 바이트 오더)
- 특정 CPU 아키텍처가 데이터를 메모리에 저장할 때 사용하는 고유의 바이트 순서.
- 즉, 시스템 내부에서 사용되는 엔디안 방식이며, 시스템 간 데이터 교환 시 반드시 고려해야 한다.
4. Network Byte Order(네트워크 바이트 오더)
- 네트워크 상에서 데이터를 전송할 때 모든 시스템이 동일한 바이트 순서를 사용하도록 정한 표준 규약이다.
- Big Endian 방식이 채택되어 있다.
5. Byte Order 처리
5-1. C++ (Windows 기준)
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
struct Packet
{
uint32_t playerID;
};
void readPacket(const char* buffer)
{
Packet pkt;
pkt.playerID = ntohl(*reinterpret_cast<const uint32_t*>(buffer));
std::cout << pkt.playerID << std::endl;
}
int main(void)
{
// 테스트용 playerID = 1205
uint32_t playerIdNetOrder = htonl(1205); // 네트워크 바이트 순서로 변환
const char* buffer = reinterpret_cast<const char*>(&playerIdNetOrder);
// 임의로 위와 같은 데이터를 받아왔다고 가정.
readPacket(buffer); // 테스트
return 0;
}
- winsock2.h의 send()는 buf가 const void *가 아닌 const char *이다. (Linux는 const void *)
- 이는 recv()도 동일하다.
5-2. Java
- C,C++은 CPU 아키텍처에 따라 Endian이 결정되는 반면 Java는 다르다.
- Java는 JVM 명세에 따라서, 일관되게 정의되어있다.
- 기본적으로는 Java Byte Code는 Big Endian으로 정의되어 있다.
※ Network Byte Order 규칙을 따른다면, Java에서는 표준 Java I/O를 사용할때, 수신된 데이터의 Byte Order를 조정할 필요가 없지만, JNI와 같은 Native Library를 사용하는 경우 변환이 필요하다고 한다.
外. 이미지 출처
- 위키피디아