как передать объект Image (или Bitmap)

 
0
 
.NET
ava
GRIENDERS | 05.11.2007, 18:37
Сервер должен передать клиенту объект Image (или Bitmap, но не файл), а клиент отобразить его в PictureBox через свойство Image
Я делаю через сериализацию, а мож еще как можно, поэффективнее?
Прочитать массив байтов, записать в поток… ну не знаю… подскажите плиз
Comments (15)
ava
stab | 05.11.2007, 20:07 #
всё просто:


image.Save(yourNetworkStream, image.RawFormat);


added later:
.. на клиенте соответственно:


pictureBox.Image = Image.FromStream(clientNetworkStream);


added later:
.. хотя может и не сработать, там seekable поток вроде нужен, если это действительно так, тогда через промежуточный MemoryStream.
ava
GRIENDERS | 05.11.2007, 21:09 #
stab, набросай код плиз, ато вот что-то у меня не так

server - все нормально

MemoryStream stream = new MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] src = stream.GetBuffer();
stream.Close();
client.GetStream().Write(src, 0, src.Length);
client.GetStream().Flush();


клиент - как узнать размер пришедших данных и прочитать их все?


const int LEN = 10000;
byte[] buffer = new byte[LEN];
client.GetStream().Read(buffer, 0, LEN);

//отображается часть картинки
MemoryStream stream = new MemoryStream(buffer);
Image img = Image.FromStream(stream);
stream.Close();
pictureBox1.Image = img;


client.GetStream().Length не поддерживается - вылетает ошибка
ava
stab | 05.11.2007, 21:35 #
перед строчкой client.GetStream().Write(src, 0, src.Length) передай размер данных, т.е:


client.GetStream().Write(BitConverter.GetBytes(src.Length), 0, sizeof(int));


на сервере соответственно её (длину) считать перед чтением изображения и использовать для опеределения количества нуждающихся в прочтении байтов. проще это всё делать через BinaryReader и BinaryWriter.
ava
GRIENDERS | 06.11.2007, 08:28 #
хорошо, спасибо stab
вот пример и парочка вопросов
server

static int client_count=0;
TcpClient my_client;

private void Form1_Load(object sender, EventArgs e)
{
IPAddress ip = Dns.Resolve(Environment.MachineName).AddressList[0];
TcpListener server = new TcpListener(ip, 5445);
server.Start();
WaitForConnection(server);
}

void WaitForConnection(TcpListener tl)
{
tl.BeginAcceptTcpClient(OnClientConnect, tl);
}

//client connect
void OnClientConnect(IAsyncResult ar)
{
++client_count;
TcpListener server = (TcpListener)ar.AsyncState;

my_client = server.EndAcceptTcpClient(ar);

Image image = GRIENDERS.Windows.Utility.GetScreen(500, 500);

MemoryStream stream = new MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] buffer = stream.GetBuffer();
stream.Close();

my_client.GetStream().BeginWrite(buffer, 0, buffer.Length, WriteToClient,
my_client);

WaitForConnection(server);
}


// тут непонятки - как часто она будет вызываться?
void WriteToClient(IAsyncResult ar)
{
my_client.GetStream().EndWrite(ar);

Image image = GRIENDERS.Windows.Utility.GetScreen(500, 500);

MemoryStream stream = new MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] src = stream.GetBuffer();
stream.Close();

my_client.GetStream().BeginWrite(src, 0, src.Length, WriteToClient,
my_client);
}






private void timer1_Tick(object sender, EventArgs e)
{
/* if (my_client != null)
{
Image image = GRIENDERS.Windows.Utility.GetScreen(500, 500);

MemoryStream stream = new MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] src = stream.GetBuffer();
stream.Close();

//client.GetStream().BeginWrite(src, 0, src.Length, WriteToClient, client);

my_client.GetStream().Write(src, 0, src.Length);
my_client.GetStream().Flush();
}*/
BinaryWriter wr = new BinaryWriter(my_client.GetStream());

}

}

1)как сделать чтобы server раз в секунду посылал клиенту эту пресловутую image? желательно без таймера, а както поэллегантнее.
2) как должна выглядеть функция void WriteToClient(IAsyncResult ar) и как часто она будет вызываться?
как мне вызвать ее принудительно?
ava
Experimenter | 06.11.2007, 13:11 #
Цитата


1)как сделать чтобы server раз в секунду посылал клиенту эту пресловутую image? желательно без таймера, а както поэллегантнее.



void ZadolbatClienta()
{
//kod, kotorym zadolbali clienta
System.Threading.Thread.Sleep(1000);
ZadolbatClienta();
}

Цитата


2) как должна выглядеть функция void WriteToClient(IAsyncResult ar) и как часто она будет вызываться?

сколько запросов от клиентов, столько и вызовов.
ava
GRIENDERS | 06.11.2007, 14:10 #
Цитата (Experimenter @ 6.11.2007, 13:11 findReferencedText)
void ZadolbatClienta()

сколько запросов от клиентов, столько и вызовов


сервер должен сам без запросов клиентов посылать им данные

Когда к серверу подрубаются, он вызывает функцию NetworkStream().BeginRead() и продолжает неспеша принимать подключения и читать данные в фоновом режиме асинхронно от уже подрубившихся клиентов так часто, как надо (как только пришли - прочитал)
А вот как надо вызвать функцию NetworkStream().BEginWrite(), чтобы сервер в фоновом режиме асинхронно без требования клиента раз в секунду посылал данные клиенту? потоки не предлагать - как нить по другому, пусть даже с таймером, мне важен пример кода (но в фоновом режиме асинхронно)
ava
GRIENDERS | 06.11.2007, 14:50 #
Цитата (Experimenter @ 6.11.2007, 13:11 findReferencedText)
сколько запросов от клиентов, столько и вызовов.

а как выглядит запрос от клиента?
ava
Experimenter | 06.11.2007, 14:53 #
т.е. всем клиентам, что подключились, начинать засылать картинку, так?
Цитата


потоки не предлагать - как нить по другому

Не совсем понял... Вызов BeginWrite() предполагает поднятие отдельного потока, как это - без потоков?
ava
GRIENDERS | 06.11.2007, 15:29 #
Цитата (Experimenter @ 6.11.2007, 14:53 findReferencedText)
т.е. всем клиентам, что подключились, начинать засылать картинку, так?

да
примерчик плиз набросай
ava
Experimenter | 06.11.2007, 15:32 #
Цитата


а как выглядит запрос от клиента?

Это абстрактно, имелось в виду - сколько подключений, столько и будет вызовов функции. Я бы зациклил посылы клиенту прямо в функции WriteToClient(), только еще бы семафор повесил, чтоб из цикла можно было выйти корректно.

added later:

callbackWrite = new AsyncCallback(this.OnWriteComplete);

private void OnReadComplete( IAsyncResult ar )
{
int bytesRead = networkStream.EndRead(ar);
if( bytesRead > 0 )
{
string s = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.Write("Received {0} bytes from client: {1}", bytesRead, s );
networkStream.BeginWrite(buffer, 0, bytesRead, callbackWrite, null);
}
else
{
Console.WriteLine( "Read connection dropped");
networkStream.Close( );
socket.Close( );
networkStream = null;
socket = null;
}
}

private void OnWriteComplete( IAsyncResult ar )
{
networkStream.EndWrite(ar);
Console.WriteLine( "Write complete");
networkStream.BeginRead(buffer, 0, buffer.Length, callbackRead, null);
}

Это от Дж. Либерти примерчик.
ava
GRIENDERS | 06.11.2007, 16:12 #
Experimenter, что не могу понять - когда и как часто будет вызываться функция посыла сообщения клиенту?
мне надо для каждого подрубившегося клиента
Цитата (GRIENDERS @ 6.11.2007, 14:10 findReferencedText)
чтобы сервер в фоновом  режиме асинхронно без требования клиента раз в секунду посылал данные клиенту


Цитата


раз в секунду посылал данные клиенту


всегда
а не только при подключении клиента
ava
stab | 06.11.2007, 17:41 #
GRIENDERS, значит тебе надо завести список адресов, который пополняется при подключении нового клиента. и на все эти адреса раз в секунду слать данные через существующее подключение или, если такового нет, через созданное на основе адреса клиента. получается активный сервер, т.е. сервер может инициировать соединения, на клиенте надо их ждать, таким же образом, как сервер ждёт соединения от клиента.
ava
tol05 | 06.11.2007, 18:28 #
что-то запутанно управление выглядит. Уже сейчас. А если в дальнейшем на программу еще навернуть functionality ... то здоровье на ее отладке и апгрейде можно здоровье потерять достаточно быстро. :)

Я советую сделать на основе remoting-а

Там все будет проще. Подконнектился клиент, или нет - не важно. Когда клиент дернет сервер (или наоборот, через событие), тогда и работа будет выполнятся.
+ меньше проблем с серилизацией.

Хотя может быть немного накладнее по памяти и более медленно...
ava
Experimenter | 06.11.2007, 18:31 #
stab, и я тоже об этом думал: либо клиент подключился и висит на канале, а сервер ему в это время что-то шлет, либо клиент должен в роли сервера выступать, для чего на всех клиентах приложение надо распространять. Видимо, Гриендерса первый случай интересует все-таки.

added later:
tol05, ему ж надо постоянно, а тут подключится-не подключится - неизвестно.

added later:
Хотя говорит, что только тем клиентам, которые подключились
В этом случае большой разницы между ремутингом и ти-си-пи клиентами не вижу.
ava
GRIENDERS | 06.11.2007, 19:40 #
Цитата (Experimenter @ 6.11.2007, 18:31 findReferencedText)
tol05, ему ж надо постоянно, а тут подключится-не подключится - неизвестно.

я имел ввиду

Цитата (Experimenter @ 6.11.2007, 18:31 findReferencedText)
что только тем клиентам, которые подключились

но не один при подключении, как во всех примерах, а постоянно

Цитата (Experimenter @ 6.11.2007, 18:31 findReferencedText)
В этом случае большой разницы между ремутингом и ти-си-пи клиентами не вижу.

беда в том, что про ремоутинг я пока мало чего знаю. ну ладно, буду капать

PS - делаю графический чат по сети (как Paint, только по сетке)
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit