2012-01-12 4 views
0

작은 이미지를 보내고받는 웹캠 앱을 만들고 있습니다. 나는 그것을 보내고받을 수있게 만들었고, 127.0.0.1에서 테스트를 해 보았지만 정상적으로 작동했다. 그러나 이제는 내 자신의 외부 IP 주소를 사용하고 있는데, 하나의 이미지를 보내고 수신 한 다음 엉망진창처럼 보인다. 이미지 크기의 거대한 정수 값, 충돌로 이어지는 마이너스 값, 아마도 수신 및 전송이 자체적으로 실행되고 있으며 어떻게 든 동기화되지 않을 것이라고 생각합니다. 나는 각 이미지를 보내기 전에 1000ms의 지연 시간을 두었고 느린 것이지만 작동하면서 지연을 제거하자마자 망가져 버렸다.TCP 패킷 전송 오류

// This sends. 
    private void NewFrameReceived(object sender, NewFrameEventArgs e) 
    { 
     Bitmap img = (Bitmap)e.Frame.Clone(); 

     byte[] imgBytes = EncodeToJpeg(img, 25).ToArray(); 
     if (_tcpOut.Connected) 
     { 
      NetworkStream ns = _tcpOut.GetStream(); 
      if (ns.CanWrite) 
      { 
       System.Threading.Thread.Sleep(500); 
       ns.Write(BitConverter.GetBytes(imgBytes.Length), 0, 4); 
       ns.Write(imgBytes, 0, imgBytes.Length); 
      } 
     } 
    } 

    // This receives. 
    private void listeningThread_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
    { 
     // start listening for connections 
     _tcpIn = new TcpListener(IPAddress.Any, 54321); 
     _tcpIn.Start(); 

     TcpClient _inClient = _tcpIn.AcceptTcpClient(); 
     while (true) 
     { 
      NetworkStream ns = _inClient.GetStream(); 
      if (ns.CanRead && ns.DataAvailable) 
      { 
       Byte[] imgSizeBytes = new Byte[4]; 
       ns.Read(imgSizeBytes, 0, 4); 
       int imgSize = BitConverter.ToInt32(imgSizeBytes, 0); 

       Byte[] imgBytes = new Byte[imgSize]; <-- ERROR, GET CRAZY LARGE VALUE 
       ns.Read(imgBytes, 0, imgSize); 

       MemoryStream ms = new MemoryStream(imgBytes); 
       Image img = Image.FromStream(ms); 

       picVideo.Image = img; 
      } 
     } 
    } 
+0

예외를 게시 할 수 있습니까? –

+0

안녕하세요, 가끔 "산술 연산 결과 오버플로가 발생했습니다." 때때로 메모리 오버플로가 발생합니다. (또한 오류 선은 아래의 행이었습니다 - 수정 됨) – sprocket12

+0

질문에 적절하게 응답 할 수있는 변수 및 알 수없는 변수가 너무 많습니다. 첫 번째 단계에서는 첫 번째 전송에서 실제로 몇 바이트가 수신되는지 확인하고 전송되는 바이트와 일치하는지 확인하는 것이 좋습니다. 이미지의 크기에 따라 전송되는 데이터 조각화가 발생할 수 있습니다. –

답변

1

Read 당신이 요구하는만큼 많은 바이트를 읽을 필요는 없습니다. 현재 많은 사람들이 이용할 수있는 것처럼 - 실제 반환 값을 확인하여 읽은 바이트 수를 확인해야합니다. documentation을 사용하면 더 나은 이해를 얻을 수 있습니다.

모든 이미지 바이트가 읽힐 때까지 읽기를 유지하려면 논리를 추가해야합니다. 의사 코드 예제 :

total_bytes_read = 0; 
while (total_bytes_read != total_bytes_needed) 
{ 
    bytes_left_to_read = total_bytes_needed - total_bytes_read; 
    total_bytes_read += read(buffer, total_bytes_read, bytes_left_to_read); 
} 
3

당신이 조금 ..... 데이터가 다른 패킷에 도착할 수있는 일을 재고 할 필요가 : 여기

는 코드입니다. 읽기 기능은 사용 가능한 것을 읽습니다. 이렇게하면 시스템이 동기화되지 않게됩니다. 시작과 이미지의 끝이 내 데이터 스트림에있는 위치를 항상 알 수 있도록

나는 이미지에 대한 약간의 프로토콜을 구축 할 것입니다.

당신이 할 필요는 없지만, 쉽게 인생을 만드는, 당신은 얼마나 그것을 가지고 이미지를 수신을 통해 알고있는 간단한 상태 머신에 의해 순수하게 그것을 할 수 있습니다. 그러나 이미지 (예 : 스트림의 1 여분의 바이트)를 전송할 때 준수하지 않을 경우 영원히 동기를 벗어날 수 있습니다.

+0

여러분의 소중한 의견에 대해 감사드립니다. 그러나 "마커 (marker)"바이트를 추가하면 1024 바이트의 블록 중간에 올 수 있습니다. 예를 들어 이전 이미지가 종료되었고 새 이미지가 시작되었음을 알 수 있습니까? 내가받은 1,024 바이트 블록의 각 바이트를 통과하여 특수 종료 플래그를 확인해야합니까? 바이트 배열 데이터에 대한 조인 및 검색 작업에 가장 적합한 클래스는 무엇입니까? – sprocket12

+1

자주 사용되는 솔루션 중 하나는 이스케이프 시퀀스를 사용하여 블록 데이터에서 시작/끝 제어 문자를 제거하는 것입니다. 또 다른 방법은 블럭 길이를 포함하는 헤더를 블럭에 접두어로 붙이면 rx가 블럭 전체를 받았을 때를 결정하고 다른 헤더를 찾기 시작할 수 있습니다. 헤더는 충분한 데이터와 중복성을 가져야 헤더가 온전한 체크를 할 수 있습니다 (예 : 항상 [SOH]로 시작하고 데이터 길이와 CRC는 고정 길이 ASCII 숫자 형식으로 포함). rx에서 byte-by-by 상태 시스템이 필요할 수 있습니다. 헤더를 확인하십시오. –