Blessing Venus

JAVA - C서버 소켓통신 처리하기 2부 본문

Tip&Tech/JAVA

JAVA - C서버 소켓통신 처리하기 2부

Blessing Venus 2017. 4. 2. 02:27

 


이번에는 ByteBuffer를 사용하여 패킷을 전송하는 방법을 알아 보겠습니다.

hello 프로토콜의 패킷 규격대로 ByteBuffer에 담아서 패킷을 송신해봅시다.

아래 예제를 볼까요!


String snack = pSnack;

String auth = pHelloClose;

short version = mVersion;

short code = 0x5001;

int callback = 0x9999;

int len = SNACK_MAX_SIZE + AUTH_MAX_SIZE; //auth의 데이터 길이

int crc = version ^ code ^ callback ^ len; //CRC 연산



Log.i("Upload", "send version : " + version);

Log.i("Upload", "send code : " + code);

Log.i("Upload", "sned callback : " + callback);

Log.i("Upload", "send len : " +len);

Log.i("Upload", "send crc : " + crc);

Log.i("Upload", "send snack : " + snack.getBytes().length);

Log.i("Upload", "send auth : " + auth.getBytes().length);



//ByteBuffer

ByteBuffer sendByteBuffer = ByteBuffer.allocate((SNACK_MAX_SIZE + AUTH_MAX_SIZE) + HEAD_MAX_SIZE); //헬로 패킷의 총 길이

Log.i("Upload", "헬로 패킷의 총 길이 : " + ((SNACK_MAX_SIZE + AUTH_MAX_SIZE) + HEAD_MAX_SIZE));

//Head 정보

sendByteBuffer.order(ByteOrder.LITTLE_ENDIAN);

sendByteBuffer.putShort(version); //2byte

sendByteBuffer.putShort(code); //2byte

sendByteBuffer.putInt(callback); //4byte

sendByteBuffer.putInt(len); //4byte

sendByteBuffer.putInt(crc); //4bye

//Auth 정보

sendByteBuffer.put(snack.getBytes());

sendByteBuffer.put(new byte[SNACK_MAX_SIZE-snack.getBytes().length]); //snack 패킷의 빈공간을 160byte에 맞게 빈바이트배열 객체로 채워줌.

sendByteBuffer.put(auth.getBytes());

sendByteBuffer.put(new byte[AUTH_MAX_SIZE-auth.getBytes().length]);

try {

dos.write(sendByteBuffer.array());

dos.flush();

}catch(Exception e) {Log.i("Upload", "Hello Packet Send Exception : " + e.toString());}


위의 예제는 Send용 ByteBuffer를 만들고 ByteBuffer에 데이터를 세팅하고,

ByteBuffer를 배열로 나열하여 전송하는 방법입니다.

사용 방법은 간단합니다.

 

//헬로 패킷의 총 길이

ByteBuffer sendByteBuffer = ByteBuffer.allocate((SNACK_MAX_SIZE + AUTH_MAX_SIZE) + HEAD_MAX_SIZE);

 

이 부분에서 ByteBuffer의 할당 공간을 정의해 줍니다.

패킷 규격에 정의된 패킷 바이트수와 딱 맞게 정의해주시면 됩니다.

예를 들어 패킷 프로토콜이 아래와 같다고 가정해 봅시다.

 

C서버 테스트패킷 프로토콜 정의

int number 번호 4byte

char[40] text 내용 40byte


위와 같이 C에서 프로토콜을 정의 하였다면 위의 순서대로 보내주시면 됩니다.

한번 해보겠습니다.

위의 테스트패킷의 총 바이트 수는 44바이트입니다.

그렇다면 우리가 보낼 ByteBuffer의 사이즈도 위와 같이 allocate 해줘야 하죠.


ByteBuffer sendBuffer = ByteBuffer.allocate(44);

 

쉽지 않나요?

그리고는 Order 설정을 해줍니다.

리틀엔디안과 빅엔디안이 있는데 

우리는 C서버와 통신을 하므로 리틀엔디안으로 세팅을 해줍니다.

 

sendByteBuffer.order(ByteOrder.LITTLE_ENDIAN);

 

이제 44Byte를 저장가능한 ByteBuffer가 생겼습니다.

이제 테스트패킷의 정보대로 임의로 데이터를 선언한 후 전송해보겠습니다.


int number = 100;

String text = "abcd";

 

위의 데이터를 ByteBuffer에 담아봅시다.

sendByteBuffer.putInt(number); //Integer 자료형은 putInt를 사용합니다.

sendByteBuffer.put(text.getBytes()); //String형은 put을 사용하며 getBytes로 바이트단위로 쪼개어 put합니다.

 

자..모두 세팅이 끝난거 같나요?

여기서 이상한 점을 발견하시지 못한다면 삽질로 고생하실 수 있습니다.

잘 살펴 보시면 C서버에서 정의한 프로토콜 규격은 44Byte입니다.

그리고 저희가 정의한 ByteBuffer의 크기 또한 44Byte입니다.

그런데 지금 저장된 Byte수는 얼마일까요?

8Byte입니다.

integer형 4byte  String text의 내용 abcd 4byte..

총 8Byte가 나오네요.

 

그럼 이대로 전송하면 괜찮을까요?

대답은 No 입니다.

왜 그럴까요?

 

C서버의 프로토콜에는 text 패킷의 크기가 40byte로 약속되어 있습니다.

그렇다면 보내는 쪽에서도 40Byte로 맞추어서 보내줘야합니다.

현재는 데이터가 4byte이므로 남은 36바이트를 빈배열로 선언하여 수치를 맞게 보내줘야 한다는 말이죠.

C서버에서는 byte 길이로 나누기 때문에 프로토콜에 정의된 사이즈를 정확히 맞춰 보내야 문제가 생기지 않습니다.

 

sendByteBuffer.put(new byte[40 - text.getBytes()]);

 

new Byte로 빈 배열을 생성하면서 사이즈는 40 - 4바이트로 주었기 때문에 36byte의 빈Byte배열이 생성되었습니다.

생성한 바이트배열 객체를 sendByteBuffer에 세팅하여 빈공간없이 맞추어 주었습니다.


sendByteBuffer.putInt(number); //Integer 자료형은 putInt를 사용합니다.

sendByteBuffer.put(text.getBytes()); //String형은 put을 사용하며 getBytes로 바이트단위로 쪼개어 put합니다.

sendByteBuffer.put(new byte[40 - text.getBytes()]);

 

그럼 위에서부터 차례대로..

4byte

4byte

36byte (빈배열)

총 44byte로 딱 맞게 맞추었습니다.

이제 세팅은 끝났습니다.

전송만 하면 된답니다.

미리 정의된 스트림을 통하여 전송합니다.
 

dos.write(sendByteBuffer.array());

 

위에 저장했던 ByteBuffer의 내용을 array로 나열하여 스트림을 통해 서버로 전송합니다.

이상입니다.

해보면 별거 없어 보이지만 처음에는 삽질도 많고 매우 까다로운 작업이랍니다.

특히 서버와 계속 확인 작업을 하며 해야 해서 여간 번거로운게 아니랍니다.

다음 3부에는 수신받은 패킷데이터를 ByteBuffer를 이용하여 다시 데이터로 복원하는 방법을 다루도록 하겠습니다.

감사합니다.

'Tip&Tech > JAVA' 카테고리의 다른 글

JAVA - C서버 소켓통신 처리하기 1부  (0) 2017.04.02
Comments