2011-01-14 3 views
1

문자열을 XElement로 파싱하여 이상한 동작을 관찰했습니다. 이제 코드XElement를 파싱하는 동안 이상한 동작이 발생했습니다.

<return value="0"> 
    <resultset> 
     <meta> 
      <column type="char(30)"></column> 
     </meta> 
     <datarow> 
      <datacol> 
       <![CDATA[master]]> 
      </datacol> 
     </datarow> 
    </resultset> 
</return> 

: 나는 시도 및 캐치 블록에 정확히 같은 일을

  try 
      { 
       xmlResult = XElement.Parse(
        _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
        LoadOptions.PreserveWhitespace); 
      } 
      catch 
      { 
       xmlResult = XElement.Parse(
        _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
        LoadOptions.PreserveWhitespace); 
      } 

먼저, 여기에 내가 구문 분석 할 XML이다.

때때로 try 블록이 XmlException ("루트 요소가 없습니다.")을 발생 시키지만 catch 블록 (정확히 똑같은 일을하는)은 throw하고 문자열을 올바르게 구문 분석하지 않습니다.

누군가 내게 이유를 말해 줄 수 있습니까?

감사합니다.

[편집] 여기

전체 방법 코드 :

private TcpClient _client; 
private NetworkStream _clientStream; 
private MemoryStream _responseBytes; 
private readonly UTF8Encoding _UTF8Encoder = new UTF8Encoding(); 
private const int BUFFER_SIZE = 1024; 

    private XElement Receive() 
    { 
     byte[] buffer = new byte[BUFFER_SIZE]; 

     XElement xmlResult; 
     Encoding serverEncoding = this.Task.Server.Encoding; 

     // Reading result 
     while (true) 
     { 
      _responseBytes = new MemoryStream(); 

      try 
      { 
       IAsyncResult e = _clientStream.BeginRead(buffer, 
        0,            // Begin 
        BUFFER_SIZE,         // Length 
        new AsyncCallback(OnBeginRead),     // Callback used 
        new SocketAsyncState(_clientStream, buffer)); // Passing buffer to callback 

       e.AsyncWaitHandle.WaitOne(); // Wait until data are in pipe 

       if (((SocketAsyncState)e.AsyncState).HasError) 
       { 
        throw new ObjectDisposedException(); 
       } 

       // Try to convert to a XElement, if fail, redo all process. 
       _responseBytes.Position = 0; 

       try 
       { 
        xmlResult = XElement.Parse(
         _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
         LoadOptions.PreserveWhitespace); 
       } 
       catch 
       { 
        xmlResult = XElement.Parse(
         _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
         LoadOptions.PreserveWhitespace); 
       } 

       // Result 100% retrieved : quit loop 
       break; 
      } 
      catch (Exception ex) 
      { 

       if (ex is ObjectDisposedException 
        || ex is XmlException) 
       { 
        while (!IsConnected) { Wait(); } // Wait that the network comes back 
        SendSyn();       // Relaunch process 
       } 
      } 
     } 

     // Result 100% retrieved : send ACK to Socket 
     SendAck(); 

     return xmlResult; 
    } 

    private void OnBeginRead(IAsyncResult ar) 
    { 
     SocketAsyncState state = ar.AsyncState as SocketAsyncState; 
     byte[] nextBuffer = new byte[BUFFER_SIZE]; 
     int numberOfBytesReaded; 
     Encoding serverEncoding = this.Task.Server.Encoding; 

     try 
     { 
      numberOfBytesReaded = state.Stream.EndRead(ar); 
     } 
     catch(Exception) 
     { 
      ((SocketAsyncState)ar.AsyncState).HasError = true; 
      // Quit 
      return; 
     } 

     // While data are available, read next buffer (recursive call to this method) 
     if (state.Stream.DataAvailable && state.Stream.CanRead) 
     { 
      state.Stream.BeginRead(nextBuffer, 
       0, 
       BUFFER_SIZE, 
       new AsyncCallback(OnBeginRead), 
       new SocketAsyncState(state.Stream, nextBuffer)); 
     } 

     // Default C# strings are in UTF-8, so convert stream only if needed 
     if (serverEncoding.CodePage != _UTF8Encoder.CodePage) 
     { 
      byte[] buffer = Encoding.Convert(serverEncoding, 
       _UTF8Encoder, 
       state.Data.TakeWhile((b) => b != '\0').ToArray()); 

      _responseBytes.Write(buffer, 0, buffer.Length); 
     } 
     else 
     { 
      _responseBytes.Write(state.Data, 0, numberOfBytesReaded); 

     } 
    } 

답변

3

당신은 무엇 _responseBytes 우리를 표시하지 않은,하지만 하나 개의 제안 스프링 마음에 : 그것은 (비동기 적으로 채워지 않다면 예를 통해 비동기 웹 요청) 데이터가 존재하기 전에 첫 번째 시도가 발생하지만 catch 블록이 실행될 때까지 데이터가 도착했을 수 있습니다.

는 (이러한 경우 물론,이 솔루션은 하지 catch 블록의 종류를 사용할 수 있지만 타이밍을 수정하는 것입니다.)

편집 : 좋아, 나는 아마도 문제를 볼 생각합니다.

e.AsyncWaitHandle.WaitOne(); 

내가 읽기가 소켓 수준에서 발생 때까지 기다릴 것입니다 의심하지만, 콜백 전에 를 호출 : 그것은 여기입니다. 귀하의 코드는 이 완료 될 때까지 대기한다고 가정합니다..

그래서 일어나고있는 (그리고 이것은 여전히 ​​추측입니다) 무슨 수 있습니다 :

주 스레드에서
  • , 당신은 작업을 킥오프하고 데이터를 읽을
  • 을 완료 할 때까지 기다리
  • WaitOne()은 주 스레드에서 반환되고 콜백은 스레드 풀 스레드에서 동시에 호출됩니다.
  • 주 스레드의 메모리 스트림에서 데이터를 구문 분석하려고합니다.
  • ... D 다음 콜백 실제로 메모리 스트림
  • 에 데이터를 기록 ... 그리고 당신이 성공 분석에서 두 번째 시도를 가지고다음 데이터는 지금
+0

편집이 참조하십시오 때문이다. 당신은 모두 비동기식으로 끝났지 만 MemoryStream이 채워지지 않았다는 것이 매우 이상한 것 같습니다 ... –

+0

@Arnaud :'_responseBytes'는 어디에 쓰여 집니까? 'buffer' 란 무엇입니까?우리가 아직 가지고 있지 않은 많은 코드가 있습니다. 질문을 짧지 만 완성 된 프로그램으로 편집 할 수 있다면 훨씬 더 쉽게 도움이 될 것입니다. –

+0

재미있는 점에 대해 감사합니다. 편집을 참조하십시오. _responseBytes가 작성되는 코드를 추가했습니다. –

관련 문제