Byte Order에 대한 정리 및 기초 복습
세상에나 마상에나.. 학교에서 치를 떨며 배웠지만 중요하게 생각하지 않았던 기초들이 칼날이 되어 돌아왔다… bit
byte
.. word
…하핳… 그래서 오늘 이에대한 정리 겸 복습을 해보고자 한다.
digital
이 뭘까? 01010101101000101010101010101001 영화 매트릭스에서도 봤던 숫자들이다. 이 디지털 세상에서는 모든 데이터가 bit
단위로 돌아간다. 즉, 디지털 세상에서는 제일 기본이 되는 단위인 bit는 0과 1밖에 표시하지 못한다. 전기신호 또한 똑같다. 5v, 0v, 5, 0v, 0v 5v, 이 또한 5는 1이 되고 0은 0이 되는 bit
단위이다.
이런 비트가 개인적으로 가장 와닿았던 곳은 네트워크를 배울때였다. A Class B class C class가 어떻니 저떻니.. 할때 192.168.0.1이 사설 주소라는 것을 알게 됐고 이 주소가 8bit.8bit.8bit.8bit로 총 32bit의 표현범위를 가진다는것을 알게됐었다. 또 2의 보수법으로 음수 표현하기라는 좋은 포스팅을 접하면서 이해도가 조금 더 높아졌었다.
Byte
그렇다면 이 byte
는 뭘까? bit 1개가 8개가 모이면 1byte로 계산한다. 라는 표준 규격에 따라 1byte는 8bit이다. 여기서 왜 하필 1byte는 8bit일까? 꼭 8bit가 아니어도 괜찮치 않은가? 여기에는 컴퓨터 아키텍처와 밀접한 관련이 있고 사실 꼭 1byte를 8bit로 규정짓지 않는 컴퓨터도 있다. 물론 옛날 컴퓨터지만.. 관련 정보들은 32비트와 64비트 포스팅을 참고하길 바란다. 여기서 컴퓨터 운영체제의 32bit, 64bit가 어떤걸 뜻하는지 진심으로 깨닳은지가 얼마되지 않았다. 이 32bit, 64bit 단위는 CPU가 사용하는 데이터를 잠시 담아놓는 레지스터
가 있는데 이 레지스터
의 최소 단위가 32bit, 64bit라는 말이다. 즉 이 운영체제의 CPU는 데이터를 처리하는 최소 단위인 레지스터
의 용량이 32bit, 64bit라는 것이다. 이 또한 더 좋은 포스팅을 참조하길 바란다.
Byte Order
여기까지 오는데 너무 많은 개념이 필요했다. 그 만큼 기초부터 차근 차근 쌓아 나아가는게 흔들리지 않는다는 것을 개발자 인생에서 또 한번 느낀다. 각설하고 Byte Order
는 말 그대로 바이트의 순서이다. 가장 효율적으로 메모리에 한번에 접근하고 읽어올 수 있는 이 4Byte
단위의 데이터를 메모리에 적재하는 방식의 차이이다. Big Endian, Little Endian의 두가지 방식이 있는데, 계란의 둥근 곳부터 깨먹는게 맞다. 계란의 뾰족한 곳부터 깨먹는게 맞다 처럼 또 엄마가 좋냐 아빠가 좋냐처럼 답이 없는듯한 개념이다. 0x01 0x02 0x03 0x04
라는 4byte를 메모리에 올릴때 최상위 바이트 MSB (Most Significant Byte)
부터 차례로 저장하는 방식이 Big Endian
이고 최하위 바이트 LSB (Least Significant Byte)
부터 차례로 저장하는 것이 Litte Endian
방식이다. Intel CPU는 Big Endian 방식을 사용하고 SPARC CPU는 Little Endian 방식을 사용한다. 참조
Network Byte Order
이처럼 저장하는 방식 부터 차이가 나므로 이 데이터를 네트워크를 통해 보내고 받을때에도 보내는 곳과 받는곳의 데이터 저장방식을 맞출 필요가 있다. 이 개념이 Network Byte Order
의 필요성이다. 최근 Network 프로그램을 작성하면서 JVM
은 기본 Bit Endian 방식으로 데이터를 저장하고 Network
또한 Big Endian 방식을 사용한다고 하기에 아무 생각없이 System.arraycopy()
로 빈공간에 SPACE
를 채우고 4byte
를 전송했더랬다. 이유도 모른체 socket의 IO Exception을 바라봐야 했고 많은 자료도 찾아봤지만 Endian방식이 문제가 아니라 이 데이터를 패킹하는 방식이 문제였다.
2의 Integer형을 패킹할때 Integer.toString("1").getByte()
로 패킹한후 1의 사이즈 만큼 arraycopy
를 수행하고 전송했는데 이것이 문제였다.
public static byte[] getBigEndianInNetwork(byte[] src) {
byte dest[] = new byte[length];
ByteBuffer bb = ByteBuffer.allocate(4);
bb.order(ByteOrder.BIG_ENDIAN);
System.arraycopy(src, 0, dest, 0, 4);
bb.put(dest);
return bb.get(0);
}
이 함수를 작성하기까지 수많은 삽질의 시간을 보냈다.. 또 최근 Network 프로그램을 작성하던 도중 기초가 헷갈리고 개념이 헷갈려 많은 삽질을 했기에 이 글을 포스팅한다. 끄.ㅅ.!