2012-01-12 2 views
0

Я делаю приложение веб-камеры, которое отправляет и получает небольшие изображения. Я сделал это, чтобы отправлять и получать, я тестировал на 127.0.0.1, и он работал нормально, но теперь я использую свой внешний внешний IP-адрес, и, кажется, он отправляет одно изображение, получает его, а затем беспорядок, я получаю какое-то массивное целочисленное значение в размере изображения, минус-значение, которое приводит к его сбою, я думаю, что, возможно, получение и отправка выполняются самостоятельно и как-то не работают. Я поставил 1000 мс задержка перед отправкой каждого изображения, и это было медленным, но работающим, как только я откладываю задержку, это испортится.Ошибка отправки пакета 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

Большое спасибо за ваше ценное предложение. Но если я добавлю какие-то «маркерные» байты, и они попадут в середину блока размером 1024 байта, как я узнаю, что старое изображение закончилось, и началось новое? Должен ли я пройти каждый байт полученного 1024 байтового блока и проверить специальный флаг? А какие классы лучше всего подходят для операций объединения и поиска по байтовым массивам? – sprocket12

+1

Одним из часто используемых решений является использование escape-последовательностей для удаления управляющих символов начала и конца из данных блока. Другим способом является префикс блока заголовком, который содержит длину блока, поэтому позволяет rx определять, когда он получил целый блок и начать поиск другого заголовка. Заголовок должен иметь достаточные данные и избыточность, чтобы позволить проверять соответствие заголовка (например, всегда начинается с [SOH], содержит длину данных и CRC в ASCII-числовой форме с фиксированной длиной). Вам может понадобиться байт-by-by by state-machine в rx. для проверки заголовка. –

Смежные вопросы