2010-12-08 4 views
7

NetworkStream에서 데이터를 임의로 보내고 데이터 패킷의 크기도 다양하게 유지해야합니다. 각 스레드가 읽을 수있는 자체 스트림이있는 다중 스레드 응용 프로그램을 구현 중입니다. 스트림에 데이터가 없으면 응용 프로그램은 데이터가 도착하기를 기다려야합니다. 그러나 서버가 데이터 전송을 완료하고 세션을 종료 한 경우 서버는 종료되어야합니다.NetworkStream.Read()와 NetworkStream.BeginRead()의 차이점은 무엇입니까?

처음에는 스트림에서 데이터를 얻기 위해 Read 메서드를 사용했지만 스레드를 차단하고 스트림에 데이터가 나타날 때까지 기다렸습니다. 원격 호스트가 연결 를 종료하고 사용 가능한 모든 데이터가 되었습니다받은 경우 MSDN의 문서에서 알 수

,

데이터가 읽을 수없는 경우

는 Read 메서드는 0을 반환 Read 메서드는 즉시 을 완료하고 0 바이트를 반환합니다.

제 경우에는 Read 메서드를 가져 와서 우아하게 종료하지 않았습니다. 그냥 무한정 기다립니다.

내가 더 조사 할 때, 데이터를 수신하자마자 스트림을 감시하고 콜백 메소드를 비동기 적으로 호출하는 BeginRead을 보았습니다. 그러나이 방법을 사용하여 다양한 구현을 시도했지만, Read과 대조적으로 BeginRead을 사용할 때를 식별 할 수 없었습니다.

내가보기에, BeginRead에는 현재 스레드를 차단하지 않는 비동기 호출이있는 장점이 있습니다. 그러나 내 응용 프로그램에서는 스트림에서 데이터를 읽고 처리하는 별도의 스레드가 이미 있으므로 그다지 큰 차이는 없습니다.

  • 누구든지 나를 BeginRead에 대한 대기 및 종료 메커니즘을 이해하는 데 도움 주실 래요과 어떻게 Read 다릅니 까?

  • 원하는 기능을 구현하는 가장 좋은 방법은 무엇입니까?

+0

리모컨이 제대로 연결을 종료하고 있습니까? 'Read'가 돌아 오지 않는 문제는 절대로 없었습니다. 그렇지 않으면 귀하의 접근 방식은 올바른 방향 인 것으로 보입니다. –

+0

@Matthew 글쎄, 솔직히 말해서 나는 그것을 확실히 말할 수 없다. 우리가 읽고있는 제 3 자 서비스입니다. 그들은 셧다운 타이밍을 명기하고 우리는 그것이 언급 된대로 일어난다 고 가정한다. 나는 단지 그들에게 깃발을 올리기 전에 내 말을 먼저 확인하고 다시 점검하기를 원한다. –

답변

10

나는 BeginRead를 사용하지만, WaitHandle 사용하여 스레드 계속 차단 :

byte[] readBuffer = new byte[32]; 
var asyncReader = stream.BeginRead(readBuffer, 0, readBuffer.Length, 
    null, null); 

WaitHandle handle = asyncReader.AsyncWaitHandle; 

// Give the reader 2seconds to respond with a value 
bool completed = handle.WaitOne(2000, false); 
if (completed) 
{ 
    int bytesRead = stream.EndRead(asyncReader); 

    StringBuilder message = new StringBuilder(); 
    message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead)); 
} 

은 기본적으로는 비동기의 제한 시간이 WaitHandle를 사용하여 읽기 수 있으며 당신에게 만약 부울 값 (completed를) 제공을 읽기가 설정된 시간 (이 경우 2000)에 완료되었습니다.

여기에 내 Windows Mobile 프로젝트 중 하나에서 복사 및 붙여 넣기 내 전체 스트림을 읽는 코드입니다 : I/O가 적은 스레드에서 I/O의 동일한 금액을 달성하기 위해 사용할 수있는 비동기

private static bool GetResponse(NetworkStream stream, out string response) 
{ 
    byte[] readBuffer = new byte[32]; 
    var asyncReader = stream.BeginRead(readBuffer, 0, readBuffer.Length, null, null); 
    WaitHandle handle = asyncReader.AsyncWaitHandle; 

    // Give the reader 2seconds to respond with a value 
    bool completed = handle.WaitOne(2000, false); 
    if (completed) 
    { 
     int bytesRead = stream.EndRead(asyncReader); 

     StringBuilder message = new StringBuilder(); 
     message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead)); 

     if (bytesRead == readBuffer.Length) 
     { 
      // There's possibly more than 32 bytes to read, so get the next 
      // section of the response 
      string continuedResponse; 
      if (GetResponse(stream, out continuedResponse)) 
      { 
       message.Append(continuedResponse); 
      } 
     } 

     response = message.ToString(); 
     return true; 
    } 
    else 
    { 
     int bytesRead = stream.EndRead(asyncReader); 
     if (bytesRead == 0) 
     { 
      // 0 bytes were returned, so the read has finished 
      response = string.Empty; 
      return true; 
     } 
     else 
     { 
      throw new TimeoutException(
       "The device failed to read in an appropriate amount of time."); 
     } 
    } 
} 
+0

감사합니다. @GenericTypeTea, 이것은 흥미로운 접근 방법처럼 보이지만 정확한 시간 초과 기간을 결정할 방법이 없습니다. 그럼에도 불구하고, 내 문제를 해결하기 위해 약간 수정할 수 있다고 생각합니다. 나는 시험해보고 성공적으로보고한다. BTW, 당신의 손잡이가 나를 웃어 줬어. :) –

+1

내가 틀리지 않으면 각 BeginABC 호출에서 항상 EndABC를 호출해야합니다. 위의 코드에서 시간 초과가 있으면 End는 호출되지 않습니다. End를 호출하고 가능한 예외를 처리하는 콜백이 위의 코드에 추가되어야합니다. – SpeksETC

+0

@ SpeksETC - 나는 당신이 틀렸다고 생각합니다. 나는 항상 end을 호출한다. int bytesRead = stream.EndRead (asyncReader);하지만 아마 bool 줄이 완료된 직후에 그 코드를 호출하도록 코드를 변경해야한다. handle.WaitOne (2000, false); 중복을 제거하기 위해 – GenericTypeTea

4

.

참고로 지금 당장 앱에는 스트림 당 하나의 스레드가 있습니다.적은 수의 연결로도 문제가 없지만 한 번에 10000을 지원해야하는 경우에는 어떻게해야합니까? 비동기 I/O에서는 읽기 완료 콜백이 관련 스트림을 식별하는 컨텍스트를 전달할 수 있으므로 더 이상 필요하지 않습니다. 읽기가 더 이상 차단되지 않으므로 스트림 당 하나의 스레드가 필요하지 않습니다.

동기화 또는 비동기 I/O 사용 여부에 상관없이 관련 API 리턴 코드에서 스트림 종료를 감지하고 처리하는 방법이 있습니다. BeginRead는 소켓이 이미 닫혀 있으면 IOException으로 실패합니다. 비동기 읽기가 보류 중일 때 폐쇄가 콜백을 트리거하면 EndRead이 재생 상태를 알려줍니다. 응용 프로그램이 그러면 BeginRead, 를 호출하면 데이터가 수신 또는 오류가 발생하고 시스템이 지정된 콜백 방법을 실행하기 위해 별도의 스레드를 를 사용하고, EndRead에 블록까지

시스템이 대기 까지 제공된 NetworkStream은 데이터 을 읽거나 예외를 throw합니다.

+0

감사합니다. 스티브. 스트림 당 하나의 스레드는 많은 다른 설계 고려 사항 때문에 발생하며 실제로는 문제가되지 않습니다. 우리는 최대 10 개의 동시 스레드를 가질 것입니다. –

0

BeginRead는 비동기 프로세스이므로 기본 스레드가 다른 프로세스에서 읽기를 시작합니다. 이제 2 개의 병렬 프로세스가 있습니다. 만약 당신이 결과를 얻고 싶다면, EndRead를 호출해야한다. 그러면 결과를 얻을 것이다.

BeginRead() 
//...do something in main object while result is fetching in another thread 
var result = EndRead(); 

일부 psudo하지만 주 스레드가 할 수있는 다른 아무것도하지 않고 u는 결과를 필요로하는 경우, u는 읽기를 호출해야합니다.

+2

여기에 여러 프로세스가 관련되어 있다는 의미는 완전히 잘못되었습니다. –

+0

@ Steve, @ Bonshington은 '프로세스'라고했을 때 '스레드'를 의미한다고 생각합니다. –

0

server.ReceiveTimeout을 시도 했습니까? Read() functon이 0을 반환하기 전에 데이터를 기다리는 시간을 설정할 수 있습니다. 귀하의 경우이 속성은 아마 무한대로 설정되어있을 것입니다.