새로운 강의는 이제 https://memi.dev 에서 진행합니다.
memi가 Vue & Firebase로 직접 만든 새로운 사이트를 소개합니다.

바로가기


Communication(통신) 1. 개념

3 분 소요

한동안 펌웨어쪽 일을 하면서 모뎀을 통해 서버쪽에 데이터를 전송하는 인터페이스를 많이 하게 되었는데..
대부분 백엔드서버 엔지니어들이 바이너리 통신을 통해 수신받아서 처리(파스)하는 부분에 상당히 무지한 것을 알았다..

미숙한 서버 개발자라서가 아니다.. 다른 부분은 다 전문적이지만 그저 바이너리 통신에 대한 경험이 없는 것이다.

예를 들어 [0x02, 0x03, 0x04] 3바이트를 서버에서 Ack를 보내줘야하는데 [0x30, 0x78, 0x30, 0x32, 0x30, 0x78, 0x30, 0x33, 0x30, 0x78, 0x30, 0x34] 12바이트를 받은 적이 있다..
이것이 무슨 의미인지 아는 개발자라면 상황의 심각성을 이해할 수 있을 것이다..
사실 이 것 때문에 이 포스트를 작성해본다..

이야기를 들어보면 대부분 http method GET,POST(RESTful API라고 보기 어려운..)를 통한 단순 http 서버(대부분 apache, iis) 데이터 처리만 해본 것이다.

아마도 이쪽 장비들(그리고 대부분의 임베디드 장비들)과 통신을 많이 안해본 듯 하다 os 포팅 안된 임베디드 장비들(http packing이 쉽지 않다.)이 내가 하는 쪽엔 95%이상이 확실하기 때문이다.

디바이스의 통신은 socket이 아닌 http로 보낼 경우 데이터 증가로 의미없는 트래픽 상승(IoT 요금제는 용량이 매우 작다)과 보안도 되지 않기 때문에 ssl(https) 적용하지 않으면 부적절한 통신 방식이라고 볼 수 있다.

대부분의 서버업체들은 전용 프로토콜을 만들어놓고 맞추라고 하지 않고 디바이스 제조사가 서버로 보내는 프로토콜이 있으면 맞추겠다 라고 하는 쪽이었다.

막상 잘 안 되어서 샘플 패킷과 내 서버 코드를 드르륵 긁어서 보내주는 일이 대부분이었다. 그래야 일이 끝나는 것이니……….. 라고 생각했지 사실 남의 코드 본다고 달라질 것은 없었다.. 이해를 하는 것이 중요한 것이지..
어짜피 메일 주고 받고 전화통화해서 설명하느니 여기 박제해버리는 것이 좋을 듯해서 저장해본다.

서버개발자들이 바이너리 tcp 프로토콜을 어려워 하는 이유는 크게 3가지였다.

  1. Byte를 잘 모른다.
    스트링으로 받은 다음(사실 바이트들) 온갖 스트링 메쏘드들을 총 출동해 파싱(특히 java)을 한다.
    실제 코드로 본 것은 이미 받은 것이 바이트(s)인데도 불구하고 그걸 다시 stringbuffer에 넣었다 split 시켰다 join 시켰다 정도의 과정을 3개 반복해서 원래의 바이트가 되는 코드를 봤다..(표현 : byte -> string -> buf -> ? -> string -> byte)
    eg1) 차속도는 한바이트로 0~255의 값을 가지고 있기 때문에 한바이트 자체가 곧 값이고 타입캐스팅만 unsigned하게 변경하면 끝난 것이었는데…
    eg2) 위에 언급한 것 처럼 서버송신을 보면 바이트를 모르는 것을 알수 있었다.

  2. 데이터를 일부러 나눠 보낸다고 생각한다.
    클라이언트 소켓으로 10000바이트를 정해서 서버에 전송 하면 대부분의 TCP 특성상 수신부 버퍼는 통신속도, 서버 세팅에 따라 다르지만 나누어 받게된다..
    이런식으로 1(2550),2(2849),3(3213),4(1388) 식으로 나뉘어 받게된다.
    이런 4개의 무작위 뭉탱이를 chunk라고 하며 백엔드 개발자들은 이미지 업로드등에서 다뤄본적이 있을 것이다..
    스트링처럼 리턴 제어문자등으로 수신완료 인식을 할 수 없기 때문에 세션동안 프로토콜로 데이터를 판단해야 한다.

  3. TCP소켓방식과 http를 완전 다른 방식으로 알고 있다.
    사실 http는 말그대로 html(하이퍼텍스트)을 전송하기 위한 규약이며 원리는 소켓통신과 같다..
    http는 간단히 socket open -> data send -> data recieve -> socket close 형태로 그중 데이터가 http 프로토콜일 뿐이고 모듈(브라우저)들이 오픈 클로즈를 자동으로 해줄 뿐이다..

한 서버 업체는 http 규격서를 보내줘서 회사에서 맞춘 적이 있다.
http method도 없는 모뎀이라 http header body(쌩 텍스트. 데이터 간격은 캐리지 리턴으로 구분)를 만들어서 POST로 보낸 것이다.
규격서에서 놀라운 것은 Ack였는데 json은 기대도 안했지만 http 기본 ‘200 OK’를 보낸다는 사실!(당연히 403 이런것도… 서버 입장에서는 은근 괜찮은데? :D)


웹서버, 스트링파서등이 처리해주는 것들을 이용하는 것이 제일 좋은 방법이지만 결국엔 스트링이라하는 것은 바이트 덩어리일 뿐이다.

string 이라는 사전적의미가 끈 이고 그냥 연결되어 있다는 것이다.(바이트들이)

네이티브 통신의 개념을 알고 라이브러리를 가져다 써야 적절한 곳에서 사용이 가능할 것이다.

그래서 정리도 할겸 내가 생각하는 통신에 대해 자료로 만들어 보기로 결정했다.

통신?

내가 서버, 장비, 모바일등 관심을 가지고 뭐든 쉽게 접근하고 만들 수 있는 이유는 모두 통신이 기반이다.

운 좋게도 나름 통신의 기초 부터 했기 때문에 단순한 원리는 알고 있다.

프로그램에 입문 전에 제일 궁금한 했던 것은 채팅창에서 “ABCD”를 전송하면 다른 사람이 “ABCD”를 어떻게 받을 것인지였다.

바이너리 통신이 바이트 통신으로 많이 알고 있지만.. 맞지도 틀리지도 않은 답이다..

실제 바이너리 통신의 뜻은 이진 통신이란 것이다. 다양한 물리적 신호(대표적인게 전기일 뿐이며 최근 박테리아로도 구현했다고 하더라는..)로 0과1을 표현해 전송할 뿐이다.

010101010100001…. 랜이든 블루투스든 와이파이든 이런 형태로 올 뿐인데 리시버들이 알아듣는 최소가 바이트라 채워서 알아들을 뿐인 것이다.

실제로 “ABCD”는 아래와 같은 형태로 오는 것이다.

alt image

직접 엑셀로 그려봤다 :/
실제 데이터를 보내면서 파형을 오실로스코프로 보면 이해가 빠르다.

RS-232(Serial) 한 비트가 속도에 따라 판단하기 때문에 속도가 안맞으면 당연히 115200bps, 9600bps 마다 다른 데이터로 판단이 되어지는 것이다

노이즈등에도 상당히 취약하다.

비트 한번 튀면 ‘A’ 가 ‘C’로 변할 수 있기 때문에 프로토콜에는 꼭 checksum, crc 등으로 유효성 판단을 해야한다.

i2c, spi는 비슷하지만 속도가 아닌 클럭과의 동기를 보고 데이터를 판단하는 정도다.

결론

오랫동안 다양한 통신을 경험했지만..

엄청나게 복잡해 보이는 통신 방식도 결국엔 이진데이터 처리를 위한 물리적인 장비(lan,wifi,bluetooth,232,spi,smb,etc…)와 프로토콜(modbus,http,ftp,ssh,etc…) 즉 약속만 있으면 되는 것이다.

한바이트 송/수신 만 확인 되면 비즈니스 로직 구현은 자연스럽게 이어진다..

eg) putchar(d) -> putstring(s) -> printp(…) -> streamp()

어떤 통신이든 한바이트가 중요한 것이다..

댓글남기기