2009-05-07 4 views
1

통신 프로토콜이 제대로 정의되지 않았기 때문에 일부 클라이언트 측 코드를 수정해야합니다.Java에서 TCP 스트림을 읽는 가장 효율적인 방법

필자는 서버의 tcp 메시지가 새 행에서 종료되어 reader.readLine()을 사용하여 데이터를 읽었을 것이라고 가정했습니다.

이제는 이것이 사실이 아니며 메시지의 처음 4 자의 문자가 메시지 길이라고 말한 다음 나머지 메시지를 읽어야합니다.

이 작업을 수행하는 가장 효율적인 방법은 무엇입니까?

  1. 메시지의 길이는
  2. 메시지 길이
  3. 의 새로운 배열을 생성 무엇인지 결정 처음 4 자에서 4 char 배열을
  4. 읽기를 만들고 다음과 같이

    내 일반적인 생각이었다

  5. 새 배열을 읽습니다.

    char[] chars = new char[4]; 
    int charCount = reader.read(chars); 
    String messageLengthString = new String(chars); 
    int messageLength = Integer.parseInt(messageLengthString); 
    chars = new char[messageLength]; 
    charCount = reader.read(chars); 
    if (charCount != messageLength) 
    { 
        // Something went wrong... 
    } 
    

    내가이 작업을 수행하는 방법을 알고,하지만 난하지가 채워지고 문자 버퍼에 대해 걱정할 필요가 수행 여기

은 (독자가 다른 곳에서 만든 BufferedReader로이다) 코드의 예입니다? 만약 그렇다면 어떻게해야합니까?

+0

프로토콜은 16 비트 Java "char"또는 8 비트 C "char"를 기반으로합니까? – McDowell

+0

다른 쪽 끝은 문자열로 읽혀지며 처음 4 자 길이가 길이입니다. 16 비트 Java Chars라고 가정합니다. 나는 서버 쪽에서 일하는 사람에게 이메일을 보내서 확인해 보겠다. –

+0

번호는 ASCII입니까? 예를 들어, 47 문자 (84 바이트)의 길이는 16 진수 문자로 표현 된 시퀀스 "0047"로 표시됩니다 (예 : 0x0030003000340047). – unwind

답변

3

Java의 문자는 텍스트 데이터입니다. 실제로 프로토콜이 메시지 길이를 정의합니까? 32 비트 길이를 나타내는 첫 번째 네 바이트 일 가능성이 큽니다.

C 또는 C++ 개발자와 이야기하는 경우 "char"를 "byte"의 동의어로 사용할 수 있습니다.

편집 : 좋아, 주석을 기반으로 :

나는 Reader와 카운트를 가져다가 맞는 정확한 양의 데이터를 읽을 때까지 반복적으로 read()라고하거나 예외를 던졌다 방법을 만들 것입니다. 이런 식으로 뭔가 :

public static String readFully(Reader reader, int length) throws IOException 
{ 
    char[] buffer = new char[length]; 
    int totalRead = 0; 
    while (totalRead < length) 
    { 
     int read = reader.read(buffer, totalRead, length-totalRead); 
     if (read == -1) 
     { 
      throw new IOException("Insufficient data"); 
     } 
     totalRead += read; 
    } 
    return new String(buffer); 
} 

는 그런 다음 코드가 될 수 있습니다

String lengthText = readFully(reader, 4); 
int length = Integer.parseInt(lengthText); 
String data = readFully(reader, length); 
// Use data now 
당신은 그들이 비록 자 미만 1,000 (이상 9999)를 보낼 때 발생하는 확인해야

...

+1

그것은 내가 생각하는 다른 끝에있는 자바 프로그래머입니다. 메시지는 문자열로 읽습니다. 문자열의 처음 4 개 문자는 메시지 길이를 나타냅니다. 나는 이것이 논리적이라고 말하는 것이 아니며, 이것이 프로토콜 작업에 대해 들었다는 것을 의미하는 것입니다 ... –

+0

Jon, 그것은 제로가되어서 1000 이하가되어서는 안되며 문제가되어서는 안됩니다. 상대방은 내가 보낸 메시지에 대한 ACK이므로 9999자를 넘지 않습니다. –

0

어 ... 유니 코드의 경우 Java에서 char은 16 비트가 아니십니까? 나는 당신이 옳은 일을하고 있다고 생각하지 않는다. chars를 사용하여 네트워크에서 오는 바이트를 표현한다. 대신 java.nio 패키지에서 ByteBuffer과 같은 것을 사용해야합니다.

단일 메시지의 최대 크기를 알고있는 경우 단일 버퍼를 만드는 것에서 멈추지 않고 4 바이트를 버퍼로 읽어 들여 int 정도로 파싱 한 다음 그 크기로 새 읽기 작업을 수행하십시오 , 버퍼 내용을 덮어 씁니다.

업데이트 : 위의 프로토콜은 2 진수이며, char의 사용은 "C-ism"이었습니다. 프로토콜이 실제로 텍스트이고 초기 4 문자 길이가 "0047"또는 "6212"와 같은 패딩 된 정수인 경우 (일부 기본에서는 10을 추측합니까?), 다음 다른 접근 방식이 더 좋을 수 있습니다. 바이트에서 문자로 이동합니다. 당신이 무엇인지 설립 한 후 문자의 특정 숫자를 읽을 필요가 질문의 일부에 관한

+0

나는 프로토콜을 정의하지 않았다. 그렇지 않으면 처음 4 바이트는 메시지가 길이가 수백만자인 메시지를 허용하는 32 비트 int 일 것이다. 그것은 내가 주어진 매개 변수 내에서 일하고 있기 때문에 ... –

1

, 다음 관용구는 java.io.Readers 공통입니다 :

int lengthToRead = getRequiredReadLength(); // Left as exercise to reader :-) 
char[] content = new char[lengthToRead] 
int from = 0; 
while (lengthToRead > 0) 
{ 
    try 
    { 
     int nRead = reader.read(context, from, lengthToRead); 
     if (nRead == -1) 
     { 
     // End of stream reached before expected number of characters 
     // read so handle this appropriately - probably throw an exception 
     } 
     lengthToRead -= nRead; 
     from += nRead; 
    } 
    catch (IOException e) 
    { 
     // Handle exception 
    } 
} 

이후 read 호출이 0이 아닌 결과를 반환하도록 보장됩니다. 데이터가 사용 가능할 때까지 스트림이 끝나거나 (-1을 반환하는 경우) 예외 블록이 호출 될 때까지 호출 블록이 차단됩니다. 스트림이 제공 할 수있는만큼 오래 필요합니다.

일반적으로 리더에서 한 번에 두 개 이상의 문자를 요청할 때 많은 문자가 실제로 제공되었다는 보장이 없으며 결과 값을 확인하기 위해 반환 값을 항상 검사해야한다는 것을 알고 있어야합니다. 그렇지 않으면 스트림의 일부가 사라지는 어떤 시점에서 필연적으로 버그가 발생하게됩니다.

관련 문제