'프로그래밍/TCP IP 통신'에 해당되는 글 1건

  1. 2014.09.12 TCP/IP_메시지 파싱 또는 프레이밍 하기-(1)

1. 비 단일 바이트 캐릭터 셋

 

 알파벳 이나 숫자, 몇가지 특수 기호 같은 경우는 다 합해 봐야 전체 문자 수가 256개를 넘지 않기 때문에, 1바이트 (8 bit)를 가지고서도 충분히 모두 표현이 가능했다. 예를들어 ASCII코드에서는, A는 0x41, a는 0x61 /는 0x2F로 표현이 가능했다. 그러나 컴퓨터가 한자나 한글 혹은 여러가지 문자들을 처리해야 함에 따라서 1바이트로 문자를 처리 하는 방식의 단점이 드러나기 시작했다.

 

 1바이트 만 가지고 256개를 넘어가는 여러 문자들을 관리 할 수 없게 된 것이다. 그래서 이 문제를 해결하고자 2바이트 이상으로 각 문자를 표현하고자 하는 캐릭터 셋이 제안되었다. 캐릭터 셋은 표현하고자 하는 문자와, 그 문자를 어떻게 bit로 표현할지 미리 정해 놓은 테이블이다.

 

대표적으로 문자를 2바이트로 대신하여 표현하는 유니코드가 있다. A는 0x0041, a는 0x0061와 같이 1바이트로 표현할 수 있었던 알파벳도 2바이트로 표현하고 그외의 모든 문자도 모두 2바이트로 표현하는 캐릭터 셋이다. 이외에도 아스키 코드는 1바이트 기타 문자는 3바이트로 표현하는 UTF-8, 아스키 코드는 1바이트로 한글은 2바이트로 표현하는 KCS5601과 같이 저마다 다른 방식으로 문자를 표현하고자 하는 캐릭터셋들이 있다.

 

2. 수신 Byte의 프레이밍 혹은 파싱

 

그런데 이런 문자의 인코딩 방식이 TCP/IP 통신에서는 골치 아픈 걸림돌이 될 수 있다. 예를들어, 내가 "한국화" 라는 문자열을 가상의 HKH-1이라는 캐릭터 셋을 이용해서 인코딩 하고 TCP/IP를 이용하여 상대편에 전송한다고 생각해보자. 아래와 같은 바이트 배열을 연결된 반대쪽에 보낸다고 생각해보자.

 

 한

 0x0001

 국

 0x0203

 화

 0x0405

 ...

 ...

<HKH-1 캐릭터 셋의 일부. 글자를 2바이트로 인코딩한다.>

 

 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}

<인코딩 된 바이트>

 

리틀 엔디언이니, 빅엔디언이니 전송하는 순서가 바뀌긴 하지만 어찌되었든 간에 보낸 순서대로 받는다고 가정하고 수신하는 쪽에서 이 바이트들을 받아서 어떻게 처리 할지 생각해보자. 단, 받는 쪽에서는 위에 인코딩 된 6바이트를 순서대로 받기는 하나 한번에 받지 못할 수도, 혹은 받을 수도 있다. 왜냐하면 TCP/IP로 전송할 때 전송하기 가장 좋은 싸이즈로 조각내어 전송하기 때문이다.

 

즉, 받는 쪽에서는 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05} 와 같이 한 무더기로 한번에 받을 수도, 혹은 아래와 같이 각 문자를 두번에 나누어, 혹은 문자를 표현하는 2바이트 중 각각의 바이트를 따로 받을 수도 있다.

 

{0x00, 0x01}

{0x02, 0x03, 0x04, 0x05}

 

<나눠서 받는 경우 1>

 

 {0x00, 0x01, 0x02}

 {0x03, 0x04, 0x05}

<나눠서 받는 경우 2>

 

나눠서 받는 경우 1의 경우를 보자. 받는 쪽에서도 HKH-1 캐릭터 셋을 알고 있으니까 이 경우 각각 "한", "국화" 라는 글자를 받아낸 바이트를 통해 알 수 있다. 그런데 문제가 있다. 받는 쪽에서 보낸 사람이 "한국화" 라는 문자열을 보낸건지 "한국화장품" 이라는 문자열을 보낸건지 알 수 있는 방도가 없다. 일단 이 문제를 어떻게 처리 할 것인지 나중에 다시 언급하고 나눠서 받는 경우 2의 경우를 보자.

 

나눠서 받는 경우 2에서는 문제가 더 심각하다. 1의 경우가 가지는 문제에 더불어 "국"을 의미했던 0x02 0x03이 따로 떨어져 있어서 한번 소켓으로 바이트를 받고 받은 바이트를 바로 HKH-1로 디코딩 (바이트를 문자로 바꿈) 할 수가 없다.

 

그럼 이 문제들을 어떻게 처리 해야 할까?

먼저 2번의 경우 생기는 문제는 아래와 같은 방법으로 풀 수 있다.

 

받은 바이트 데이터를 바이트 배열에 계속 차곡 차곡 쌓는다. 

 

이 방법을 통해 인코딩된 2바이트가 따로 수신되더라도 두 바이트를 연계해서 의미해석이 가능해진다. 1 경우 생기는 문제를 해결 하는 방법으로는 아래의 방법이 있다.

 

1. 미리 보내고 받는 쪽 모두 몇바이트를 보낼 것인지 사전에 약속하기 

2. 몇바이트를 보낼 것인지 먼저 전송하기 (starter)

3. 문자가 끝났음을 알리는 바이트 전송하기 (sperator, delimiter 혹은 지시자)

 

먼저, 1은 미리 3글자만 보낸다고 알려주는 것이다. 그러면 받는 쪽에서 무조건 6바이트만 HKH-1로 디코딩하여 글자로 만들면 된다. 그런데 실제 TCP를 이용하는 곳에서는 써먹기가 어렵다. 보내고자 하는 정보가 3글자로 제한되기 때문이다.

 

2번째 방법은 미리 '<', '>' 와 같은 지시자를 이용하여 몇바이트를 보낼지 전송하는 것이다. 전송받은 바이트를 차곡차곡 쌓아가면서 이 바이트 배열에 '<' , '>' 사이에 들어있는 값을 HKH-1로 디코딩 하여 앞으로 추가로 더 오게되는 정보가 몇바이트 인지 알려주는 방법이다. 예를 들어, 아래와 같이 "한국화"를 전송할 수 있다.

 

"<6>한국화" == { 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}

 <

0x0607 

 6

0x0809

 >

0x0A0B

 한

0x0001 

 국

0x0203

 화

0x0405

 ...

 ...

 

 

 

 

 

 

 

 

 

 

 

그럼 수신하는 쪽에서는 0x0607과 0x0A0B를 찾아서 그 사이에 있는 값을 HKH-1로 디코딩하여 앞으로 오는 몇바이트가 실제로 송신단에서 보낸 문자열인지 알 수 있게 된다.

 

3번째 방법은 보내는 문자열 다음에 문자열의 끝을 알리는 지시자를 전송하는 방법이다. 예를 들어 지시자로 "<>"를 쓴다고 한다면 전체 전송하는 문자열은 "한국화<>" 가 되고 실제 전송되는 바이트는 아래와 같다.

 

한 

 0x0001 

0x0203

0x0405

<

0x0607

>

0x0809

...

 ...

 

이렇게 2, 3번을 통해 실제 의미있는 데이터 범위를 정하는 과정을 프레이밍 또는 파싱 작업이라고 하는데, 이걸 실제로 구현하려고 하면 썩 생각만큼 녹록치가 않다. 아래와 같은 기능들을 직접 구현해야 하기 때문이다.

 

1. 나눠서 받는 데이터를 저장할 수 있는 byte 구조

2. byte구조에서 starter 혹은 delimiter를 검색할 수 있는 기능

3. 필요한만큼 byte구조에서 데이터를 빼고 나머지 데이터를 다시 byte구조에 옮기는 기능

   Queue의 Dequeue 기능과 비슷하나 1바이트가 아닌 복수개의 바이트를 움직이는 점이

   다르다.

 

링크를 통해 연습삼아 구현해 본 코드를 살펴 볼 수 있다. (비공개)

Posted by 굿쟌
,