2010-08-03 2 views
1

소켓 위에 프로토콜을 작성 중이므로 헤더를 구현 한 다음 정보를 전송하기로 결정했습니다. 따라서 서버에 연결 당 하나의 스레드가 있고 거기에 헤더에 읽음이 있고 거기에 도착할 때 나머지 정보를 읽는 방법에 위임합니다.Java의 소켓 위에 프로토콜을 작성하는 데 문제가 있습니다.

그래서 본질적으로는 다음과 같습니다

while ((length = inStream.read(buffer)) != -1) 
{ 
    dispatch(buffer, length); 
} 

그래서 디스패치 방법은 다음 헤더와 대의원 헤더에서 발견 된 내용 따라 방법을 해독합니다.

byte[] clearText = decrypt(message,length); 
if (cleartext == foo) sendFooToSocket(); 

그런 다음 sendFooToSocket()이 거기에 앉아서 인스 트림에서 읽거나 아웃 스트림으로 전송합니다. 이것은 내가 몇 가지 문제를 일으키는 것처럼 보입니다. 클라이언트에서 헤더를 보낸 다음 나머지 데이터를 보내는 중입니다. 그러나 모든 것이 하나가되어 헤더로 나뉘어 데이터가 나타나지 않는 것으로 보입니다. 또한 sendFooToSocket 메서드를 강제 종료하는 가장 좋은 방법은 무엇입니까?

public void sendFooToSocket() 
{ 
    byte[] buffer = new byte[1024]; 
    int length = 0; 
    while ((length = inStream.read(buffer) >0) 
    { 
    message = decrypt(buffer, length); 
    } 
} 

플러시로 인해 스트림을 열 때이 메소드를 중단 할 수 있습니까?

그래서 두 가지 문제가 있습니다. 내 메시지가 파손되지 않는 것처럼 보이고 플러시가 sendFooToSocket()과 같은 메소드를 삭제할 수있는 것처럼 보이지 않습니다.

byte[] header = "MESG".getBytes(); 
cipher = encrypt(header); 
outStream.write(cipher,0,cipher.length); 
outStream.flush(); 
byte[] message = "Hi server".getBytes(); 
cipher = encrypt(message); 
outStream.write(cipher,0,cipher.length); 
outStream.flush(); 

을하지만 그것이 모든 쓰기 후 플러시 비록 1 메시지로 서버에 의해 수신 :

명확성을 위해, 클라이언트는이한다. 보내는 것만으로 헤더가 작동하고 sendFooToSocket() 메서드가 작동하지 않게됩니다. 그러나 플러시 후에 데이터를 보내면 즉시 처리됩니다.

클라이언트는 socket.get의 OutputStream 및 InputStreams를 사용합니다. 클라이언트는 OutputStream과 InputStream도 사용합니다. 이것이 중요한지 확실하지 않은가요?

답변

3

"기록 경계"가 원하는 것 같습니다. 일반적으로 스트림에는 암묵적인 레코드 경계가 없습니다. 이런 종류의 기능을 원한다면, 입력을 버퍼링하고, 레코드의 끝을 나타내는 줄 바꿈을 찾아 직접 구현해야합니다.

BufferedInputStream을 살펴보십시오.

+0

그래서 플러시가 호출 되더라도 버퍼링됩니까? 그래서 당신은 플러시에 의존 할 수 없습니까? 또는 수신 측에서 데이터를 버퍼링하지 않을 수 있습니까? – dekz

+0

flush()는 보류중인 모든 데이터를 강제로 보냅니다. 다른 끝에서 read()는 차단 해제되어야합니다. 그러나 read()가 반환 할 때 파이프에있는 모든 것을 확실히 제어 할 수는 없습니다. 따라서 레코드 경계를 관리해야합니다. – seand

+1

모든 flush()는 파일 시스템 (이 경우 데이터는 디스크에 커밋되어야 함) 또는 네트워크 (데이터가 대기중인 경우)에 관계없이 데이터가 하위 수준 드라이버로 전달된다는 것을 보증합니다. 전송 용). 전송이 궁극적으로 어떻게 발생하는지에 대한 제어권이 없습니다. –

1

inStream.read()는 메시지 경계에서 반환하지 않을 수 있습니다. 특정 경계 (예 : 헤더와 내용을 구분하는 빈 줄과 같은 경우)로 반환한다고 가정 할 수 없습니다. 내용을 수동으로 구문 분석하고 해당 내용을 무시해야합니다 여러 개의 read() 또는 한 개의 read()가 헤더와 내용을 모두 포함 할 수 있습니다.

+0

그래서 새로운 행이 나올 때까지 읽는 read() 메서드를 쉽게 다시 작성한 다음 올바른 메서드로 스트림을 전달합니다. 새로운 회선을 보내는 것보다 메시지를 보내는 것보다 더 우아한 해결책이 있습니까? 아니면 그냥 그렇게 못생긴 보이지 않는 메시지 통신을 포장해야합니다. – dekz

1

구현 한 레벨에서 실제로 제어하지 않으려면 Object 스트림 (ObjectInputStream 및 ObjectOutputStream 참조)을 고려할 수 있습니다. 이러한 스트림을 사용하면 소켓을 통해 Java 객체를 보내고 헤더 및 경계 등을 처리하지 않고도 다른 끝에서 읽을 수 있습니다.자세한 내용은 ObjectOutputStream를 참조하지만, 꽤 많이있다 :

보낸 사람 : 의 writeObject (objectX)

수신기 : myCopyOfObjectx = readObject에()

당신은만큼 (당신이 좋아하는 물건을 보낼 수 있습니다 그들은 Serializable이다).

+0

직렬화 된 객체에는 잡았다가있을 수 있습니다. Java (또는 사용중인 플랫폼)로 제한됩니다. 데이터가 불투명합니다. 통신 프로토콜이 간단하기 때문에 텔넷/ncat을 테스트 용 리스너에 연결할 수 있으므로 유용합니다. – seand

관련 문제