Актуальность вопроса.
В рунете я не видел статей, которые поднимали бы эту проблему, не считая локальных обсуждений на различных форумах. Зачем вообще нужно учить программу что-то передавать серверу? Ну допустим, вы закинули клиент на свой второй ПК. Программа снимает видео небольшими фрагментами или же фотографирует экран в определённое время, после чего ей нужно отослать эти фотографии на сервер, а иначе как вы их удалённо увидите? Или же нам нужно передать какой-либо файл с нашего сервера на наш клиент, непростая задача? Отталкиваясь от этого примера, мы сегодня научим сервер передавать изображения клиенту, в следующем уроке разберём, как клиенту передать что-то на сервер.
Самое главное, что сегодня мы будем работать со стандартными компонентами - TcpServer и TcpClient (вкладка Internet). Почему с ними? Потому что передавать буффер (или поток данных, или файл, если совсем грубо) через компоненты, рассмотренные в прошлом уроке - весьма муторно. Это мы рассмотрим в следующий раз.
Первое, что нужно понимать - это то, как передаются изображения или другие любые файлы. Этот вопрос я подробно рассмотрел в статье
Тем не менее напомню, что любой файл возможно передавать в структуре типа TStream (Поток). Что она из себя представляет? Это поток (а грубо говоря массив) байт, который, в зависимости от предназначения умеет выполнять те, или иные функции. Если мы работает с обычными бинарными файлами, то возможно использовать простую структуру TStream, если же работаем, например, с текстом - то можно использовать потомки TStream, заточенные под текст (TStringStream), если работаем с памятью ПК, то используем TMemoryStream и так далее. Вся структура потомков класса TStream представлена ниже:
Почитать о классах можете в Google :)
Таким образом получаем план работ:
1) Научить программу делать ScreenShot'ы экрана
2) Положить полученный ScreenShot в поток байт
3) Передать поток на сервер
На самом деле всё не так уж и сложно. Поехали.
1) Как делать ScreenShot экрана на делфи? Способов существует огромное количество, я написал следующий код:
var bmp:TBitmap; // Переменная типа TBitMap
begin
bmp := TBitmap.Create; //Инициализируем
bmp.Width := Screen.Width; //Ширину задаём шириной экрана
bmp.Height := Screen.Height; //Высоту задаём высотой экрана
BitBlt(bmp.Canvas.Handle, 0,0, Screen.Width, Screen.Height, //Копируем содержимое экрана в переменную
GetDC(0), 0,0,SRCCOPY);
form1.Image1.Width := Screen.Width;
form1.Image1.Height := Screen.Height;
form1.Image1.Picture.Assign(bmp); // Выгружаем переменную в объект Image
bmp.Free;
end;
Проверка:
2) Теперь напишем код для процедуры Execute у компонента IdTCPServer, где мы будем получать команду от клиента и посылать ему ScreenShot:
var
BM:TJPEGImage;
cmd:string;
Stream:TMemoryStream;
bmp:TBitmap;
begin
cmd:=AContext.Connection.IOHandler.ReadLn; //считываем команду
memo1.Lines.Add('клиент '+AContext.Binding.PeerIP+' послал команду: '+cmd);
if cmd='Give_Image' then //если клиент запросил картинку
begin {тот самый код ScreenShot'а}
BM:=TJPEGImage.Create;
Stream:=TMemoryStream.Create;
//скриншот
bmp := TBitmap.Create;
bmp.Width := Screen.Width;
bmp.Height := Screen.Height;
BitBlt(bmp.Canvas.Handle, 0,0, Screen.Width, Screen.Height,
GetDC(0), 0,0,SRCCOPY);
bm.Assign(bmp);
//скриншот
bm.SaveToStream(stream);
Stream.Position:=0;
//передаём картинку
try
AContext.Connection.IOHandler.Write(Stream,Stream.Size,true);
finally
AContext.Connection.Disconnect;
BM.Free;
Stream.Free;
end;
end;
end;
Форма Server'а содержит обычный компонент memo, который является журналом подключения:
Теперь сделаем форму для клиента, которая будет содержать лишь компонент Button, для запроса ScreenShot'а и компонент Image, для выгрузки полученного изображения:
Код кнопки "Получить":
var Stream:TMemoryStream;
BM:TJPEGImage;
begin
Stream:=TMemoryStream.Create;
BM:=TJPEGImage.Create;
form1.IdTCPClient1.Host:='127.0.0.1';
form1.IdTCPClient1.Port:=7777;
try
form1.IdTCPClient1.Connect;//пытаемся соединится
form1.IdTCPClient1.IOHandler.WriteLn('Give_Image'); //посылаем команду на сервер
form1.IdTCPClient1.IOHandler.ReadStream(Stream); //считываем данные
Stream.Position:=0;
BM.CompressionQuality:=100;
BM.LoadFromStream(Stream); //Выгружаем поток
image1.Picture.Bitmap.Assign(BM); //Выгружаем переменную в Image
finally
form1.IdTCPClient1.Disconnect; //разорвали соединение
BM.Free;
Stream.Free
end;
end;
Так же не забыли, что у Сервера нужно выставить свойство DefaultPort, поставив туда значение "7777", а так же свойство Bindings, указав там "0.0.0.0:7777". Ну и само собой Active ставим на true :)
Проверим?
Как видим всё удачно передалось. Что бы посмотреть полное изображение, нужно было растянуть форму :) Программу можно доработать, сделав её невидимой, или же наоборот, заставив клиента нам слать изображения на сервер. Экспериментируйте и успехов вам!