Эффективный способ отправки изображений через WCF? - PullRequest
24 голосов
/ 02 декабря 2009

Я изучаю WCF, LINQ и некоторые другие технологии, написав с нуля специальное приложение для дистанционного управления, такое как VNC. Я создаю его с тремя основными целями:

  1. Сервер обеспечит «дистанционное управление» на уровне приложения (т.е. бесшовные окна) вместо полного доступа к рабочему столу.
  2. Клиент может выбрать любое количество приложений, запущенных на сервере, и получить поток изображений каждого из них.
  3. Клиент может подключиться к нескольким серверам одновременно.

Сейчас я использую WCF для отправки массива байтов, который представляет отправляемое окно:

using (var ms = new MemoryStream()) {
    window.GetBitmap().Save(ms, ImageFormat.Jpeg);
    frame.Snapshot = ms.ToArray();
}

Реализация GetBitmap:

var wRectangle = GetRectangle();
var image = new Bitmap(wRectangle.Width, wRectangle.Height);
var gfx = Graphics.FromImage(image);

gfx.CopyFromScreen(wRectangle.Left, wRectangle.Top, 0, 0, wRectangle.Size, CopyPixelOperation.SourceCopy);

return image;

Затем он отправляется клиенту через WCF (TCPBinding и всегда будет через локальную сеть) и восстанавливается в пустой форме окна без такой границы:

using (var ms = new MemoryStream(_currentFrame.Snapshot))
{
    BackgroundImage = Image.FromStream(ms);
}

Я хотел бы сделать этот процесс как можно более эффективным при использовании как процессора, так и памяти, с пропускной способностью на третьем месте. Я хочу, чтобы клиент подключился к 5+ серверам с 10+ приложениями на сервер.

Является ли мой существующий метод лучшим подходом (продолжая использовать эти технологии), и могу ли я что-то сделать для его улучшения?

Идеи, которые я изучаю (но у меня нет опыта):

  • Использование графической библиотеки с открытым исходным кодом для захвата и сохранения изображений вместо .Net решения.
  • Сохранение в формате PNG или другого типа изображения, а не JPG.
  • Каждый раз отправлять дельты изображения вместо полного изображения.
  • Попробуйте «записать» окна и создать сжатый видеопоток вместо снимков изображения (mpeg?).

Ответы [ 7 ]

21 голосов
/ 10 декабря 2009

Вы должны знать об этом:

  • Транспорт: TCP / двоичное кодирование сообщений будет самым быстрым способом передачи данных изображения
  • Захват изображения: вы можете использовать P / Invoke для доступа к данным на экране, так как это может быть быстрее и занимать больше памяти. Некоторые примеры: Захват изображения экрана в C # [P / Invoke] , Как сделать снимок экрана с помощью .NET [Managed] и Захват снимков экрана с помощью C # (Managed)
  • Вам следует уменьшить данные изображения перед его отправкой;
    • мудро выбирайте формат изображения, так как некоторые форматы имеют собственное сжатие (как JPG)
    • пример должен быть Найти различия между изображениями C #
    • отправка только разностного изображения, вы можете обрезать его и просто отправить непустые области
  • Попробуйте проверить ваши сообщения WCF. Это поможет вам понять, как форматируются сообщения, и поможет определить, как сделать эти сообщения меньше.

Просто после , пройдя через все эти шаги и будучи удовлетворенным вашим окончательным кодом, вы можете загрузить VncSharp исходный код . Он реализует протокол RFB (запись в Википедии) , "a simple protocol for remote access to graphical user interfaces. Because it works at the framebuffer level it is applicable to all windowing systems and applications, including X11, Windows and Macintosh. RFB is the protocol used in VNC (Virtual Network Computing)."

4 голосов
/ 10 декабря 2009

Я работал над похожим проектом некоторое время назад. Это был мой общий подход:

  • Растрирует захваченное растровое изображение до тайлов 32x32
  • Чтобы определить, какие листы изменились между кадрами, я использовал небезопасный код для сравнения их 64-битных за раз
  • На множестве дельта-плиток я применил один из фильтров PNG для улучшения сжимаемости и добился наилучших результатов с фильтром Паэта
  • Используется DeflateStream для сжатия отфильтрованных дельт
  • Используется BinaryMessageEncoding Пользовательская привязка к службе для передачи данных в двоичном формате вместо версии по умолчанию в кодировке Base64

Некоторые соображения на стороне клиента. При работе с большими объемами данных, передаваемых через службу WCF, я обнаружил, что некоторые параметры HttpTransportBinding и XmlDictionaryRenderQuotas были установлены в довольно консервативные значения. Так что вы захотите увеличить их.

4 голосов
/ 02 декабря 2009
1 голос
/ 06 декабря 2009

Самый быстрый способ отправки данных между клиентом / сервером - это отправка байтового массива или нескольких байтовых массивов. Таким образом, WCF не нужно выполнять какую-либо пользовательскую сериализацию для ваших данных.

Это сказал. Вам следует использовать новую библиотеку WPF / .Net 3.5 для сжатия ваших изображений вместо изображений из System.Drawing. Функции в пространстве имен System.Windows.Media.Imaging работают быстрее, чем старые, и все еще могут использоваться в winforms.

Чтобы узнать, подходит ли сжатие, вам нужно сравнить свой сценарий, чтобы узнать, как сравнивается время сжатия / распаковки с передачей всех несжатых байтов.

Если вы передаете данные через Интернет, то сжатие наверняка поможет. Преимущество между компонентами на одном компьютере или в локальной сети может быть не столь очевидным.

Вы также можете попробовать сжать изображение, затем разбить данные на части и отправить асинхронно с идентификатором чанка, который вы задаете вместе на клиенте. Соединения Tcp запускаются медленно и со временем увеличивают пропускную способность, поэтому запуск двух или четырех одновременно должен сократить общее время передачи (все в зависимости от того, сколько данных вы отправляете). Разделение байтов сжатых изображений также проще с точки зрения логики по сравнению с созданием тайлов на реальных изображениях.

Подведены итоги : System.Windows.Media.Imaging должна помочь вам как с точки зрения производительности процессора, так и пропускной способности по сравнению с вашим текущим кодом. Память мудрая, я бы догадался о том же.

0 голосов
/ 08 апреля 2011
Bitmap scrImg = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics scr;
scr.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.PrimaryScreen.Bounds.Size);
testPictureBox.Image = (Image)scrImg;

Я использую этот код для захвата экрана.

0 голосов
/ 06 декабря 2009
  1. Ваше решение выглядит хорошо для меня, но я предлагаю (как и другие) использовать плитки и при возможности сжимать трафик. Кроме того, я думаю, что вы должны посылать все изображение время от времени, просто чтобы быть уверенным, что дельты клиента имеют общую «базу».

  2. Возможно, вы можете использовать существующее решение для потоковой передачи, такое как RTP-H263 для потоковой передачи видео. Он отлично работает, использует сжатие, хорошо документирован и широко используется. Затем вы можете пропустить часть WCF и перейти непосредственно к потоковой части (либо через TCP, либо через UDP). Если ваше решение будет запущено в производство, возможно, потоковый подход H263 будет лучше с точки зрения скорости отклика и использования сети.

0 голосов
/ 02 декабря 2009

Вместо захвата всего изображения просто отправьте меньшие подразделы изображения. Значение: начиная с верхнего левого угла, отправьте изображение размером 10x10 пикселей, затем «переместите» десять пикселей и отправьте следующий квадрат размером 10 пикселей и т. Д. Затем вы можете отправить десятки небольших изображений, а затем обновить окрашенное полное изображение на клиенте. Если вы использовали RDC для просмотра изображений на удаленном компьютере, вы, вероятно, видели, что он выполняет такой вид рисования экрана.

Используя меньшие разделы изображения, вы также можете разделить дельты, поэтому, если ничего не изменилось в текущем разделе, вы можете безопасно пропустить его, сообщить клиенту, что пропускаете его, а затем перейти к следующему разделу .

Вы обязательно захотите использовать сжатие для отправки изображений. Однако вам следует проверить, получаете ли вы файлы меньшего размера от сжатия, подобного gZip, или если использование кодека изображения дает вам лучшие результаты. Я никогда не проводил сравнения, поэтому не могу точно сказать, так или иначе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...