2017-12-22 20 views
-1

종속 환경 : Windows 10 OS에서 JAVA를 사용하여 TCP 서버를 만들었습니다. 내 TCP 클라이언트 프로그램은 VC++로 작성되었으며 Windows 7 OS에서 실행됩니다 (코드의이 부분을 제어 할 수는 없으며 블랙 박스입니다).TCP 패킷 수신이 비정상 인 경우

내 TCP 서버 코드는 다음과 같다 :

Socket s = ss.accept(); 
s.setReceiveBufferSize(2000); 
s.setSendBufferSize(2000); 
s.setTcpNoDelay(true); 
s.setKeepAlive(true); 
new TcpConnectionHandler(s,this.packetHandler); 

다음은 TCP 연결 핸들러 조각입니다 :

InputStream incomingPacketBuffer = this.clientSocket.getInputStream(); 
OutputStream outgoingPacketBuffer = this.clientSocket.getOutputStream(); 
int bufferLen=0; 
byte inBuffer[] = new byte[this.clientSocket.getReceiveBufferSize()]; 
byte outBuffer[] = new byte[this.clientSocket.getSendBufferSize()]; 
while(this.clientSocket.isConnected()) 
{ 
    bufferLen = incomingPacketBuffer.read(inBuffer); 
    if(bufferLen>0) 
    { 
     outBuffer = (byte[]) this.packetHandlerModule.invoke(this.packetHandler,Arrays.copyOf(inBuffer, bufferLen)); 
    } 
    if(outBuffer != null) 
    { 
     if(this.clientSocket.isConnected()) 
     { 
      outgoingPacketBuffer.write(outBuffer); 
      outgoingPacketBuffer.flush(); 
     } 
    } 
} 
this.clientSocket.close(); 

통신은 패킷 기반 및 프로토콜/구문 분석이 처리됩니다 에 의해 packetHandler. 내가 해봤

두 더 변종 :

  1. 나는 응답을 클라이언트에게 보내기로 때 소켓을 닫 노력했다. 즉, 하나의 데이터 패킷을받은 후 클라이언트에 응답하고 연결을 닫습니다.

  2. read 방법을 사용하기 전에 inputStream.available을 사용했습니다.

I 직면하는 문제점 : TCP 서버 초 이내에 들어오는 패킷에 대한 응답 시간의 대부분

. 서버가 유휴 시간 후에 패킷을 수신하면 서버는 패킷에 응답하지 않습니다. 때로는 활성 통신이 진행 중이더라도 응답이 전송되지 않는 경우가 있습니다. 둘째, isConnected 함수는 클라이언트 소켓이 연결을 닫은 경우에도 true를 반환합니다.

디버깅 시도 : 나는 패킷을 전송 teraterm을 사용하고 체크

  1. . 행동은 동일합니다. 패킷을 하나씩 보내면 문제가 없습니다. 한 패킷이 응답을받지 못하면 그 이후에 전송 된 모든 패킷은 서버로부터 응답을받지 못합니다.

  2. 서버 콘솔에서 Ctrl + C를 누르면 teraterm에서 보낸 모든 패킷이 TCP 서버에서 처리되고 응답이 다시 전송됩니다. 그 후 서버는 일정 기간 동안 제대로 작동합니다.

  3. wireshark를 사용하여 패킷 흐름을 확인했습니다. 응답이 정상적으로 반송되면 클라이언트 요청 (SYN, SYN + ACK, ACK, PSH, PSH + ACK, FYN, FYN + ACK, ACK)의 ACK와 함께 전송됩니다. 응답이 staled되면 (올바른 용어가 아닐 수도 있고, inputStream.available 또는 inputStream.read에 멈춤), ACK 패킷 만 서버 (SYN, SYN + ACK, ACK, PSH, ACK)에 의해 전송됩니다.

  4. 많은 포럼과 다른 스레드를 stackexchange에서 확인하고, Nagle의 알고리즘에 대해 알았으며, applicaion은 TCP에서 패킷 화를 처리해야하며 TCP는 8 + 12 또는 15 + 5 또는 그와 같은 방식으로 10 + 10 패킷을 수신 할 수 있습니다. 서버 코드는 패킷 화를 처리하며 setKeepAlive이 true로 설정됩니다 (서버에서 패킷을 보낼 때 문제가 없습니다).짧은

문제 : ". 시간에, TCP는 전화가 수신 패킷이 경우에도 오랜 기간 Ctrl + C를 누르면는 처리지고 차단하기 읽기."

추신 : 방금 stackexchange에 대한 쿼리를 게시하기 시작 했으므로 질문을 공식화하는 방법에 문제가 있는지 알려 주시기 바랍니다.

PPS : 그런 긴 게시물에 대해 죄송합니다.

UPDATE

  1. EJB에서 주석은 피어 분리를 식별하기 위해 저를 도왔다.

  2. 서버용 운영 체제로 우분투 16.04를 사용하여 다른 설정을했습니다. 그것은 3 일되었습니다, 윈도우 시스템은 가끔 문제가있었습니다. 우분투 16.04는 결코 훼손되지 않았습니다.

+1

'isConnected()'는 테스트중인 지점에서 false가 될 수 없습니다. 이것은 피어 단절 테스트는 아니지만 -1을 반환하는'read()'는 무시하고 있습니다. – EJP

+0

@EJB, 감사합니다. 이것은 연결을 제대로 닫는 데 도움이되었습니다. – Raavanan

+0

도움이 될 것이라고 확신하지만 질문에 코드에 반영되지 않았습니다. '무기한 오래되었다'는 것은 무엇을 의미합니까? – EJP

답변

0

몇 가지 고려 사항;

  • TCP 버퍼 크기는 일반적으로 적어도 8K이며 적어도 2000 바이트로 채울 수 있다고 생각하지 않습니다. 가능하다면 좋은 생각이라고 생각하지 않습니다.
  • 의 크기는 약 2K를 넘지 않아도됩니다. 값을 선택할 수도 있습니다.
  • 버퍼를 두 번 이상 만들 필요가 없습니다.

그래서 짧게 시도 할 것입니다. 때때로

Socket s = ss.accept(); 
s.setTcpNoDelay(true); 
s.setKeepAlive(true); 
new TcpConnectionHandler(s,this.packetHandler); 

try { 
    InputStream in = this.clientSocket.getInputStream(); 
    OutputStream out = this.clientSocket.getOutputStream(); 
    int bufferLen = 0; 
    byte[] buffer = new byte[2048]; 
    while ((bufferLen = in.read(buffer)) > 0) { 
     out.write(buffer, 0, bufferLen); // not buffered so no need to flush 
    } 
} finally { 
    this.clientSocket.close(); 
} 

은, TCP는 수신 패킷이 경우에도 호출이 오랜 기간 동안 차단하기 읽기.

Java의 동작으로 인한 것이 아닌지 확인하기 위해 테스트 Java 클라이언트를 작성할 수 있습니다.

+0

입력 해 주셔서 감사합니다. 나는 매번 버퍼 생성이 필요 없다는 것을 이해합니다. 그러나 주요 문제는 여전히 남아 있습니다. 내 패킷의 최대 크기는 200 바이트로 제한되어 있으므로 현재 2k로 처리 할 수 ​​있습니다. 앞서 언급했듯이 테라 텀을 사용하여 TCP 프로토콜을 사용하여 서버에 연결합니다. 또한 무작위로이 블록을 얻습니다. 여기 키는 Ctrl + C로 끝났습니다. 내가 터미널을 방해 할 때 패킷이 제공됩니다. – Raavanan

+0

@Raavanan 위의 코드는 원하는 것을 수행해야합니다. 어떤 경우에 이것을 증명하기 위해 Java 클라이언트를 작성합니다. 귀하의 터미널 프로그램이 이상한 일을하는지는 모르겠습니다. –

+0

문제는 터미널과 관련이 없으므로 터미널을 사용하여 다른 사례를 확인했습니다. 어쨌든, 운영체제는 또한 제가 생각할 때 약간의 차이를 만듭니다. 업데이트를 참조하십시오. – Raavanan