2012-10-26 3 views
3

특정 헤더 및 데이터 본문을 필요로하는 C 응용 프로그램과 소켓을 통해 연결하려고합니다. 그러나 해당 형식을 따르려고 할 때 여러 가지 문제가 발생합니다. 그것은 다음과 같아야합니다 :JAVA - 사용자 정의 소켓 프로토콜 작업

헤더 :
- 패킷 시작을위한 2 바이트.
- 패킷 크기와 헤더를 나타내는 4 바이트.
- 패킷 유형에 대해 1 바이트.

본문 :
- 매개 변수의 양을 나타내는 4 바이트.

각 매개 변수에 대해 하나의 블록 :
- 매개 변수 경도에 대해 4 바이트.
- 메시지 내용의 X 바이트
- 이스케이프 문자의 경우 1 바이트.

[%%] 13 00 00 00] [0] [12 00 00 00] [0B 00 00 00] [OPERATIONPERFORMED \ 0]

: 여기

서버가 기다리고 있는지의 예

내가 겪고있는 문제는 PrintWriter를 통해 정보를 보내려고 할 때 상대방이 16 진 값을 실제 값 대신 ASCII 문자로 가져 오는 것입니다. ByteBuffer, DataOutputStream 및 여러 옵션을 사용하여 이미 시도해 보았지만 여전히 형식이 이상하거나 더 이상합니다.

내가 조사한 바에 따르면 엔디안이 반대로되어 올바른 바이트를 갖지만 잘못된 순서로 나타납니다.

지금 노력하고있어 구현은 다음과 같다 :

DataOutputStream stream = new DataOutputStream(socket.getOutputStream()); 
    PrintWriter writer = new PrintWriter(socket.getOutputStream()); 

    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

    // Header 
    stream.writeChar(37); 
    stream.writeChar(37); 
    stream.writeInt(26); 
    stream.writeChar('\\0'); 

    stream.writeInt(1); 
    stream.writeInt(11); 

    stream.writeUTF("SET_PROBLE\\0"); 


    stream.flush(); 

    StringBuilder sb = new StringBuilder(); 

    boolean state = true; 

    while (state) { 
     if (in.ready()) { 
      sb.append((char) in.read()); 
     } 
     else { 
      if (sb.length() > 0) { 
       state = false; 
      } 
     } 
    } 

    System.out.println(sb.toString().trim()); 

} 

당신이 나를 도울 수 있습니까?

미리 감사드립니다.

+0

코드의 중요 부분을 포함하십시오 – amphibient

+5

문자 또는 직렬화 된 객체가 아닌 * 바이트 *를 보내는 원시'OutputStream'을 사용해야합니다. –

+1

누군가가 "텍스트"작가를 사용하고있는 것처럼 들립니다. wireshark와 같은 도구를 사용하여 전송 된 것에 대한 가정이 올바른지 확인하는 것이 좋습니다. –

답변

2

Tomasz는 당연히 OutputStream을 직접 사용하고 바이트를 보내는 것에 대해 정확합니다. 나는 이것을 확장하여 이것이 사실 인 이유를 설명하고자합니다.

서버에서 예상하는 바이트를 검토해 보겠습니다. 우선, 값 37 (ascii %%) 각각 2 바이트가 필요합니다. DataOutputStream.writeChar은 당신에게 그것을주지 않을 것입니다. 워드 프로세서로서 명확하게 Writes a char to the underlying output stream as a 2-byte value, high byte first.

stream.writeChar(37); 
stream.writeChar(37); 

4 바이트 될 것이다 주 : 0 (37) 0 (37) (00 25 00 25 헥스). 마찬가지로 여러 개의 4 바이트 정수가 필요합니다. 서버 샘플을 기반으로 이러한 정수는 리틀 엔디안 모드로 직렬화됩니다 (낮은 바이트 먼저). 그래서 DataOutputStream.writeIntWrites an int to the underlying output stream as four bytes, high byte first이기 때문에 도움을주지 않을 것입니다.

(1A 00 00 00)이 필요할 때 4 바이트 - 0 0 0 26 (또는 00 00 00 1A 16 진수)가됩니다. 당신은 아이디어를 얻습니다. 이것은 단지 작동하지 않을 것입니다.

다음은 DataOutputStream을 버리고 OutputStream을 직접 사용하여 이러한 문제를 해결할 수있는 방법을 보여주는 몇 가지 샘플 코드입니다.우리는 16 진수 값을 출력하고 사용자의 요구 사항과 일치하는지 보여줄 수 있도록

public static void myWriteInt(OutputStream out, int value) throws IOException 
{ 
    out.write(value % 0xff); 
    out.write((value >> 8) % 0xff); 
    out.write((value >> 16) % 0xff); 
    out.write((value >> 24) % 0xff); 

} 
public static void main(String[] args) throws Exception 
{ 

    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    // Replace with 
    // OutputStream out = socket.getOutputStream() 

    out.write((byte) 37); 
    out.write((byte) 37); 

    myWriteInt(out, 26); 
    out.write((byte) 0); 

    myWriteInt(out, 1); 
    myWriteInt(out, 11); 

    out.write("SET_PROBLE\0".getBytes("UTF-8")); 

    System.out.println(DatatypeConverter.printHexBinary(out.toByteArray())); 

내가있는 ByteArrayOutputStream에 쓰고 소켓을 처리하지 않도록합니다. 소켓 출력 스트림으로 바꾸면됩니다.

다음 또한 I 포함했다 마지막 청크가 0

의해 SET_PROBLE 이어진다

2525 1A000000 00 01000000 0B000000 5345545F50524F424C4500 

(I는 명확성을 위해 일부 공간에 추가) 맞춤 리틀 엔디안 INT 마샬 아웃이 코드 인쇄

(myWriteInt)하지만, Little Endian 모드로 설정된 임시 ByteBuffer를 사용하는 것과 같은 다른 접근 방식이 있습니다.

희망이 도움이됩니다.

+0

정말 도움이되었습니다. 시간과 큰 도움에 감사드립니다. – bassprodukt

관련 문제