문제

Tomcat에서 메시지를 보내고 받기 위해 원격 서버에 양말을 만들었습니다. 원격 컴퓨터에서 메시지를 받기 위해 작업 전용 스레드를 사용했습니다 (이 스레드 만 소켓에서 읽지 않습니다).

일부 바이트가 Socketchannel에서 수신되면 (새 데이터의 비 차단 모드에서 Socketchannel을 계속 폴링하는 경우), 다음 메시지의 길이를 얻기 위해 4 바이트를 읽은 다음, Socketchannel에서 x 바이트를 할당하고 읽습니다. 그런 다음 디코딩하고 메시지로 재구성했습니다.

아래는 수신 스레드에 대한 내 코드입니다.

@Override
public void run() {

    while (true) { //Don't exit thread

        //Attempt to read the size of the incoming message
        ByteBuffer buf = ByteBuffer.allocate(4);

        int bytesread = 0;
        try {
            while (buf.remaining() > 0) {
                bytesread = schannel.read(buf);

                if (bytesread == -1) { //Socket was terminated

                } 

                if (quitthread) break;
            }

        } catch (IOException ex) {

        }

        if (buf.remaining() == 0) {
            //Read the header
            byte[] header = buf.array();
            int msgsize = (0xFF & (int)header[0]) + ((0xFF & (int)header[1]) << 8)
                    + ((0xFF & (int)header[2]) << 16) + ((0xFF & (int)header[3]) << 24);

            //Read the message coming from the pipeline
            buf = ByteBuffer.allocate(msgsize);
            try {
                while (buf.remaining() > 0) {
                    bytesread = schannel.read(buf);

                    if (bytesread == -1) { //Socket was terminated

                    }

                    if (quitthread) break;
                }
            } catch (IOException ex) {

            }

            parent.recvMessage(buf.array());
        }

        if (quitthread) {
            break;
        }
    }

}

Socketchannel에서받은 첫 번째 바이트는 괜찮으며 메시지를 성공적으로 해독했습니다. 그러나 다음에 Socketchannel에서 읽을 때 소켓은 약 100 바이트를 건너 뛰었으므로 잘못된 바이트를 읽고 길이로 해석하여 모든 것이 손상되었습니다.

코드에 무슨 문제가 있습니까? Socketchannel에서 다른 스레드가 읽지 않습니다.

도움이 되었습니까?

해결책

괄호가 꺼져 있고 코드는 다음과 같습니다.

(0xFF & ((int)header[1] << 8))

항상 0 (<< 16 및 << 24와 동일)입니다. 제 생각에는 다음과 같습니다.

((0xFF & ((int)header[1])) << 8)

이것은 충분한 메시지 바이트를 읽지 않고 동기화에 불일치로 이어질 것입니다 (너무 많은 것을 읽는 것과는 달리).

편집하다: 이제 위의 내용을 수정하면 잘못된 것을 볼 수 없습니다. 첫 번째 메시지의 길이와 먹는 바이트의 정확한 수 사이의 관계를 알려 주시겠습니까?

표시된 코드를 기반으로, 내 유일한 추측은 Schannel에 영향을 줄 수있는 샘플에서 일부 동작을 편집했다고 생각합니다. Schannel은 다른 곳에서 참조됩니까?

라인 인 경우 :

ByteBuffer buf = ByteBuffer.allocate(4);

외부에있을 것입니다 while 그것은 당신이 설명하는 행동을 초래하지만 샘플 코드에서는 그렇지 않습니다.

다른 팁

비 블로킹 모드에서 소켓을 폴링한다고 말할 때 "표준"을 사용하고 있음을 의미합니다. Selector.select() 접근하다?

SELECT가 반환되고 소켓에서 읽을 수있는 데이터가 있음을 나타내는 경우 선택 ()에 호출을 다시 입력하기 전에 사용할 수있는 바이트 만 읽어야합니다. read ()가 -1을 반환하면 버퍼에서 즉시 판독 할 수있는 더 이상 바이트를 사용할 수 없음을 나타냅니다. 소켓이 닫혔다는 의미는 아닙니다. 따라서 반환하기 전에 버퍼를 완전히 채우려는 시도가 잘못되었다고 생각합니다. 작동하더라도 데이터가 도착하는 동안 I/O 스레드가 지속적으로 회전됩니다. 특히, 단순히 -1의 반환 값을 무시하고있는 것 같습니다.

유한 상태 머신 접근법을 사용하려면 코드를 재건하는 것을 고려하십시오. 예를 들어, 과거에는 3 국가 모델을 사용하여이를 구현했습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top