2015-01-14 16 views
0

입니다. 다음 코드는 List<byte[]>()을 통해 반복되지만, 어떤 이유로 인해 lengthBuffer가 다른 크기의 byteData가되는 경우가 있습니다.데이터 바이트와 다른 크기를 반환하는 GetBytes가 실제로

BitConverter.ToInt32() 길이를 인쇄 한 다음 실제 byteDataList[i].Length을 인쇄하는 DebugPrintInGame 메서드에서 볼 수 있습니다.이 두 숫자는 정확히 동일해야하며 많은 시간이 있어야하지만 알 수없는 이유 때문에 지금은 그들도 아니다.

아래 코드는 서버의 데이터 길이를 서버로 보내 서버가 들어오는 데이터의 크기와 예상되는 크기를 알 수 있도록 실제 데이터를 전송합니다. 그러나 예를 들어 가끔은 실제 데이터가 전송 된 것보다 더 큰 길이를 전송할 것이지만 무작위로 발생하기 때문에 스레드 문제 일 수 있습니다. 그럼에도 불구하고 byteDataList는이 스레드 내에서만 사용되므로 잠글 수도 있습니다. 그것. 내가 테스트 한 내용에서 보내는 데이터는 2kb ~ 17kb입니다.

누구나 내 프로젝트의이 작은 스 니핏을 기반으로 이런 일이 일어날 수있는 이유를 알 수 있습니까? 이 코드는 모두 클라이언트 측입니다. 알림 BitConverter.ToInt32(lengthBuffer, 0)byteDataList[i].Length은 동일한 길이를 제공 할 것으로 예상되지만 그렇지 않습니다. 그게 문제 야. 이 경우에도 서버로 전송되기 전에 클라이언트 측에서

List<byte[]> byteDataList = new List<byte[]>(); 
//......... 

lock (byteDataList) //pointless lock, just used for random testing :\ 
{ 
     if (byteDataList.Count > 0) 
     { 
      for (int i = 0; i < byteDataList.Count; i++) 
      { 
       try 
       { 
         byte[] lengthBuffer = BitConverter.GetBytes(byteDataList[i].Length); 
         //quick printout to compare lengths for testing 
         this.QueueOnMainThread(() => 
         { 
         Tools.DebugPrintInGame("Length buffer " + lengthBuffer.Length + 
               + BitConverter.ToInt32(lengthBuffer,0)+ " "+ 
               + byteDataList[i].Length); //this should be same as BitConverter lengthBuffer 
         }); 
         //send length 
         stream.Write(lengthBuffer, 0, lengthBuffer.Length); 
         //send data 
         stream.Write(byteDataList[i], 0, byteDataList[i].Length); 
         stream.Flush(); 
        } 
        catch (Exception ex) 
        { 
         this.QueueOnMainThread(() => 
         { 
          Tools.DebugPrintInGame("Exception " + ex.ToString()); 
         }); 
        } 
      } 

     } 
} 

인쇄 아웃 :

Notice different lengths?

공지 사항 다른 길이 지난 2가 동일해야합니다. 즉,

`lengthBuffer` = 17672 
`byteDataList[i]` = 17672 

하지만 때로는이 이상하고 불안정한 이동 :

`lengthBuffer` = 17672 
`byteDataList[i]` = 2126 

모두 lengthBuffer 및 byteDataList는 [내가] 동일해야합니다.

+0

예, 'byte [] Array.Length'는 바이트 배열의 크기를 바이트로 나타냅니다. – Euthyphro

+0

그렇다면 배열 요소를 보내고 있습니다. 요소의 길이가 전송 된 후 실제 요소가 전송됩니다. 코드를보고 [i]를 확인하십시오. – Euthyphro

+0

디버깅 목적을 위해 데이터 배열의 시작 부분에 길이를 추가해야한다고 생각합니다. int의 표현은 항상 같은 길이가 될 것이므로 다른 끝에서 읽고 검사하여 대기 시간/네트워크 문제가 아닙니다. 아니면 당신의 인쇄물에 그 골반이 보이십니까? – kmcc049

답변

1

이 (난 당신이 .NET 4.0 또는 이전 버전을 사용하고있는 가정?) 루프에서 i 변수를 통해 폐쇄와 가장 가능성이 문제가되는 원인은 여기에 있습니다 :

this.QueueOnMainThread(() => 
         { 
         Tools.DebugPrintInGame("Length buffer " + lengthBuffer.Length + 
               + BitConverter.ToInt32(lengthBuffer,0)+ " "+ 
               + byteDataList[i].Length); //this should be same as BitConverter lengthBuffer 
         }); 

당신이 참조하는 방법을 참조하십시오 변수 i? 위의 익명 메소드는 해당 변수에 대해 클로저를 형성합니다. 즉, i은 메소드가 호출 될 때까지 평가되지 않습니다. 즉, i의 값은 lengthBuffer를 만드는 데 사용한 값이 아니므로 불일치가 발생합니다.

이렇게, 루프 내측의 범위에서 가변으로 i의 복사본을 저장이 문제를 해결하려면

int k = i; 
this.QueueOnMainThread(() => 
          { 
          Tools.DebugPrintInGame("Length buffer " + lengthBuffer.Length + 
                + BitConverter.ToInt32(lengthBuffer,0)+ " "+ 
                + byteDataList[k].Length); //this should be same as BitConverter lengthBuffer 
          }); 

를 내부 범위 변수 걸쳐 개폐함으로써, 의도 한 값과 원을 갖 루프가 실행될 때 변경되지 않습니다. 여기서 혼란은 실제로 루프 변수가 클로저의 목적을 위해 루프 본문 범위를 벗어나는 것으로 간주된다는 것입니다. 이후 버전의 C# (.NET 4.5 용)에서는이 동작이 변경되었으며 루프 변수가 내부 범위로 닫힙니다. 그들은 이런 상황에서 정확하게이 문제를 해결하기가 너무 쉽기 때문에 변화를 만들었습니다.

+0

예 .net 2.0을 사용하여 고마워요! 이제 왜 서버가 예상보다 적은 데이터를 받고 있습니다. – Euthyphro

+0

@Euthyphro, 모든 TCP 패킷이 도착할 때까지 충분히 기다려야합니까? 단일 수신은 패킷 경계를 넘는 경우 모든 데이터를 가져올 수 없으므로 완전한 메시지가있을 때까지 데이터를 버퍼링하고 수신해야합니다. 하지만 크기를 명시 적으로 알고있는 경우 대부분의 TCP API는 정확히 N 바이트가 수신 될 때까지 차단하는 방법을 제공합니다. –

+0

서버에서 나는 .net 2.0이 붙어 있지 않으므로'var initialBuffer = new byte [4];를 사용합니다. var lengthBuffer = receiveStream.ReadAsync (initialBuffer, 0,4);를 기다린다. 들어오는 데이터의 길이를 얻고'var bytesRead = receiveStream.ReadAsync (requestBuffer, 0, requestLength);를 기다린 후 예상 길이에 따라 실제 데이터를 수신하려면 requestLength = BitConverter.ToInt32 (initialBuffer, 0); 이것은 차단되어야 기다리는 나의 이해입니다. 크기가 같지 않으면 예외가 발생합니다. – Euthyphro