2012-08-28 3 views
2

SslStream을 사용하여 일부 소켓 레이어에서 작업. referenceSslStream.Read()의 이상한 동작

나는 간단한 클라이언트를 구현했다. 어색한 부분은 응용 프로그램을 실행할 때 서버가 클라이언트에 응답하지 않는 것입니다.

디버그 화면으로 이동하여 일부 중단 점을 설정하면 끝이없는 루프에있는 것이이 기능임을 깨달았습니다.

static string ReadMessage(SslStream sslStream) 
{ 
    // Read the message sent by the server. 
    // The end of the message is signaled using the 
    // "<EOF>" marker. 
    byte [] buffer = new byte[2048]; 
    StringBuilder messageData = new StringBuilder(); 
    int bytes = -1; 
    do 
    { 
     bytes = sslStream.Read(buffer, 0, buffer.Length); 

     // Use Decoder class to convert from bytes to UTF8 
     // in case a character spans two buffers. 
     Decoder decoder = Encoding.UTF8.GetDecoder(); 
     char[] chars = new char[decoder.GetCharCount(buffer,0,bytes)]; 
     decoder.GetChars(buffer, 0, bytes, chars,0); 
     messageData.Append (chars); 
     // Check for EOF. 
     if (messageData.ToString().IndexOf("<EOF>") != -1) 
     { 
      break; 
     } 
    } while (bytes != 0); 

    return messageData.ToString(); 
} 

추가 조사는 여기에 실제 범죄를 지적 : SslStream.Read()는 반환하지 않습니다, 같은

bytes = sslStream.Read(buffer, 0, buffer.Length); 

보인다. 디버그 화면에서 byte[] buffer을 확인하면 응답이 crlf까지 buffer에 기록되었음을 알 수 있습니다. 이 기능은 작업을 완료했지만 여전히 성공으로 돌아 가지 않습니다!

왜 이런 이유가있을 수 있습니까? 이 문제를 해결하기 위해 어떤 단계를 밟아야합니까?

또한 회의의 경우 : 서버가 정상적으로 작동하는지 확인하기 위해 openssl을 사용했으며 모든 것이 서버 측에서 문제가되지 않습니다.

참고 : 나는 이미 SslStream.ReadTimeout 속성에 대해 알고 있습니다. exception을 제기하여 작업을 수행하지만 모든 시나리오에서 올바른 대답은 아닙니다. 특히 서버가 while 루프와 버퍼를 사용하여 효율적으로 읽을 수있는 대량의 데이터 스트림으로 응답하는 경우에 적합합니다.

+0

SslSocket.BeginRead/EndRead를 사용하여 다른 동작이 발생합니까? –

+0

나는 그것을 아직 시험하지 않았다, 내가 그것을 조사하게 해주세요. @PeterRitchie –

답변

1

연결이 열려 있고 서버가 <EOF>으로 작성되지 않은 경우 서버가 "매달아 져있는"것입니다. 더 많은 데이터를 기다리고 있습니다. 더 이상 데이터가 없다는 것을 알 수있는 유일한 방법은 서버가 연결을 종료하는 것입니다.

서버가 실제로 보낸 모든 데이터를 이미 읽을 수 있습니까? 무슨 messageData전에 전에는 돌아 오지 않는 전화처럼 보이는가요?

+0

서버가 ''으로 응답을 성공적으로 끝냈다 고 응답했습니다. 'debug' 화면을 살펴보면 그 사실을 확인할 수 있습니다. –

+1

예, 'crlf'까지 모든 데이터를 읽을 수있었습니다. '.Read()'가 멈추었 기 때문에'messageData'는 아무것도 보이지 않습니다.'timeout'을 추가하면'messageData'는 서버가 리턴 한 모든'response'를 포함하고 있습니다. –

-1

몇 가지 생각을하고 나서 해결 방법을 찾았습니다.

sslStream.ReadTimeout = 100; //How much time does it takes for a processor to read and write 2048bytes to the buffer? 

아무 것도 작동하지 않는 것 같습니다. 예외 처리를 위해 독자를 수정했습니다.

static string ReadMessage(SslStream sslStream) 
{ 
    // Read the message sent by the server. 
    // The end of the message is signaled using the 
    // "<EOF>" marker. 
    byte[] buffer = new byte[2048]; 
    StringBuilder messageData = new StringBuilder(); 
    int bytes = -1; 

    do 
    { 
     try 
     { 
      bytes = sslStream.Read(buffer, 0, buffer.Length); 

     } 
     catch (Exception ex) 
     { 
     } 
     // Use Decoder class to convert from bytes to UTF8 
     // in case a character spans two buffers. 
     Decoder decoder = Encoding.ASCII.GetDecoder(); 
     char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)]; 
     decoder.GetChars(buffer, 0, bytes, chars, 0); 
     messageData.Append(chars); 
     // Check for EOF. 
     if (messageData.ToString().IndexOf("\r\n") != -1) 
     { 
      break; 
     } 

    } 
    while (bytes != -1); 



    return messageData.ToString(); 
} 

이 방법이 유용 할지라도 좋은 대답은 아닙니다. 누군가가 더 나은 답변을 제공 할 수 있다면 좋을 것입니다.

1

나는 나와 같은 문제로 어려움을 겪고 있었다. 프로그램은 무한 루프였다. 당신은 HTTP, HTTPS 프로토콜을 사용하는 경우

나는 다음과 같은 정보

을 통해 해결?"가까운 \ r에 \ n 연결"

Http Standart Article

14.10 연결

Connection 일반 헤더 필드는 특정 연결 및 MUST을 위해 요구되는 옵션을 지정하는 송신자 수 있습니다 당신은 헤더에 추가 더 이상 연결을 통해 프록시가 전달하지 마십시오.

Connection = "Connection" ":" 1#(connection-token) 
    connection-token = token 

HTTP/메시지가이 분야에서 각 연결 토큰, 전달 및되기 전에 Connection 헤더 필드를 구문 분석하는 모든 헤더 필드를 제거해야 1.1 프록시 (:

Connection 헤더는 다음과 같은 문법을 가지고 s)을 연결 토큰과 같은 이름의 메시지에서 가져옵니다. 연결 옵션은 해당 추가 옵션의 헤더 필드가 아닌 Connection 헤더 필드에있는 연결 토큰의 존재에 의해 신호를받습니다. 연결 옵션과 관련된 매개 변수가없는 경우 추가 헤더 필드가 전송되지 않기 때문입니다.

Connection 헤더에 나열된 메시지 헤더에는 Cache-Control과 같은 종단 간 헤더가 포함되어서는 안됩니다.

HTTP/1.1은 응답 완료 후 연결이 닫힐 것임을 알리는 발신자의 "닫기"연결 옵션을 정의합니다. 예를 들어, 요청 또는 응답 헤더 필드에

**Connection: close** 

이 연결이 현재의 요구 후`지속 '(8.1 절)로 간주되어서는 안 나타냅니다/응답이 완료됩니다.

영구 연결을 지원하지 않는 HTTP/1.1 응용 프로그램은 모든 메시지에 "닫기"연결 옵션을 포함해야합니다.

이 필드의 각 연결 토큰에 대해 Connection 헤더가 포함 된 HTTP/1.0 (또는 하위 버전) 메시지를 수신하는 시스템은 같은 이름의 메시지에서 모든 헤더 필드를 제거하고 무시해야합니다 연결 토큰으로 이렇게하면 pre-HTTP/1.1 프록시에 의해 이러한 헤더 필드를 잘못 전달하는 것을 방지 할 수 있습니다. 19.6.2 절을 보라.