Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Локальная сеть


Автор: Tokagero 25.10.2006, 18:07
Итак, идея в том чтоб сделать прогу, которая с определенного сервера локальной сети передавала картинки на несколько других компов в сети, причем без открывания локального доступа и т.д. Сделать программу которая ложит картинку в опред. открытый каталог а другой комп копировал - элементарно. Надо чтоб этого небыло. Чтоб компы каким-то образом коннектились и серв передавал, компы получали. Помогите  smile 

Автор: drkot 25.10.2006, 18:17
На компах получателях поднимаеш серверные сокеры (думаю UDP лучший вариант)
На компе передатчике поднимаеш клиентский сокет и транслируеш с него инфу (какую угодно) в виде широковещательных послок.
Самый простой вариант воспользоваться indy9. меньше заморочек и разобраться не сложно.

Автор: Tokagero 25.10.2006, 18:25
А можно мне написать пример. Я в этом  smile а оно надо. Допустим, чтоб комп-серв отсылал какую-то картинку на 2 других компа?? Чтоб попроще

Автор: Tokagero 27.10.2006, 08:45
Ага. Значит, я немного разобрался с УДП. Я непонял несколько вещей:
1) Порт. Что это за штука, как его определить и т.д.
2) Как оформить передачу файлов сразу на несколько компьютеров, а не на 1.
Код

unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, XPMan, ComCtrls, IdUDPClient,
  IdBaseComponent, IdComponent, IdUDPBase, IdUDPServer, IdSocketHandle;

type
  TMainForm = class(TForm)
    OpenBtn: TButton;
    FileEdit: TLabeledEdit;
    SendBtn: TButton;
    GroupBox1: TGroupBox;
    SizeCap: TLabel;
    BufCount: TLabel;
    ProgressBar: TProgressBar;
    StatusLabel: TLabel;
    SizeLabel: TLabel;
    BufLabel: TLabel;
    UDPServer: TIdUDPServer;
    OpenDialog: TOpenDialog;
    UDPClient: TIdUDPServer;
    SaveDialog: TSaveDialog;
    procedure OpenBtnClick(Sender: TObject);
    procedure SendBtnClick(Sender: TObject);
    procedure UDPServerUDPRead(Sender: TObject; AData: TStream;
      ABinding: TIdSocketHandle);
    procedure UDPClientUDPRead(Sender: TObject; AData: TStream;
      ABinding: TIdSocketHandle);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;
  get_accept: boolean = false;
  ServerStream : TFileStream;
  first_       : boolean=true;
  get_buffers  : integer;
  get_buf_num  : integer;
implementation

{$R *.dfm}

procedure SendProcedure(FStream: TFileStream; UDPClient: TIdUDPServer;
           StatusLabel :Tlabel; ProgressBar :TProgressBar);
var
  i,j,count: integer;
  buf : array[1..40000] of Char;
begin
  i:=round(FStream.Size/40000);
  if (i*40000<FStream.Size) then i:=i+1;
  ProgressBar.Max:=i;
  UDPClient.Send('localhost',1151,'count_buf:'+IntToStr(i)+'#');
  Application.ProcessMessages;
  for j:=1 to  i do
  begin
    if i=j then
    count:=FStream.Read(buf,FStream.Size-((i-1)*40000))
    else count:=FStream.Read(buf,length(buf));
    UDPClient.SendBuffer('localhost',1151,buf,count);
    StatusLabel.Caption:='ïåðåäà÷à ïàêåòà ¹ '+IntToStr(j);
    ProgressBar.Position:=j;
    while get_accept=false do Application.ProcessMessages;
    get_accept:=false;
  end;
end;

procedure TMainForm.OpenBtnClick(Sender: TObject);
var
  FStream : TFileStream;
begin
  if OpenDialog.Execute
  then
   begin
    FileEdit.Text:=OpenDialog.FileName;
    FStream:=TFileStream.Create(OPenDialog.FileName,fmOpenRead);
    SizeLabel.Caption:=IntToStr(Round(FStream.Size/1024))+' êèëîáàéò.';
    BufLabel.Caption:=FloatToStr(FStream.Size/40000)+' ïàêåòîâ.';
    FStream.free;
   end; 
end;

procedure TMainForm.SendBtnClick(Sender: TObject);
var
  FStream : TFileStream;
begin
  if not FileExists(FileEdit.Text) then Exit;
  FStream:=TFileStream.Create(FileEdit.Text,fmOpenRead);
  SendProcedure(FStream, UDPClient, StatusLabel, ProgressBar);
  FStream.Free;
end;

рrocedure TMainForm.UDPServerUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
  str_buf : array[1..20] of Char;
begin
  if first_=true then
  begin
    AData.Read(str_buf,length(str_buf));
    if copy(str_buf,1,10)='count_buf:' then
    get_buffers:=StrToInt(copy(str_buf,11,pos('#',str_buf)-11));
    if SaveDialog.Execute then
    begin
      first_:=false;
      ServerStream:=TFileStream.Create(SaveDialog.FileName,fmCreate);
    end;
  end else
  begin
    get_buf_num:=get_buf_num+1;
    ServerStream.Position:=ServerStream.Size;
    ServerStream.CopyFrom(AData,AData.Size);
    UDPServer.Send('localhost',1152,'accept');
    if get_buffers=get_buf_num then
    begin
      ShowMessage('Âñå, ïðèíÿòî!');
      ServerStream.Free;
    end;
  end;
end;

procedure TMainForm.UDPClientUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
begin
  get_accept:=true;
end;

end.

Это я нашел. Не помню, где. Прошу обяснить как ТУТ это переоборудовать. И кКак оформить передачу файлов сразу на несколько компьютеров, а не на 1.

Автор: drkot 27.10.2006, 11:21
Цитата(Tokagero @  27.10.2006,  08:45 Найти цитируемый пост)
Порт. Что это за штука, как его определить и т.д.

Если сравнить комп с многоэтажным домом, то порт это дверь (или окно) через которое проходит информация адрессованная конкретному потоку.
Порт нужно не определять, а задавать. Межеш выбрать практически любое число от 10000 до 65000.

Цитата(Tokagero @  27.10.2006,  08:45 Найти цитируемый пост)
Как оформить передачу файлов сразу на несколько компьютеров, а не на 1.

смотри метод boardcast (отсылает широковещательные пакеты на все компьютеры подсети).


Цитата(Tokagero @  27.10.2006,  08:45 Найти цитируемый пост)
Прошу обяснить как ТУТ это переоборудовать.

Перво наперво разделить серверную и клиенсткую часть.

Код

UDPClient.Send('localhost',1151,'count_buf:'+IntToStr(i)+'#');
заменить на 
UDPClient.Broadcast('count_buf:'+IntToStr(i)+'#',1151,);

и по аналогии для передачи тела файла.

PS: порт можно оставить тотже

Автор: Tokagero 27.10.2006, 12:51
Цитата(drkot @  27.10.2006,  11:21 Найти цитируемый пост)
и по аналогии для передачи тела файла.

?? Мне то и надо обяснить, куда собсно вписатть тело файла. Допустим, надо передать файл "c:\pic.jpg"

Автор: Tokagero 27.10.2006, 14:13
Единственное что теперь надо это способ передачи тела самого файла. 
Цитата(Tokagero @  27.10.2006,  12:51 Найти цитируемый пост)
Допустим, надо передать файл "c:\pic.jpg"

Можно это как-то в двух строчках продемонстрировать??
И вы говорили, send заменить на broadcast... А что на что  тогда менять у "получателя"??

Автор: drkot 27.10.2006, 14:59
У получателя все останется как было.

есть два типа функции send
в одном указавается адресс получателя, а в другой нет.
тебе нужна функия без адреса получателя (boardcast) + одноименное свойство компонента boardcast:=true.

И думаю болеше ничего менять не надо.
Освобожусь и подправлю твой исходник.

Автор: Tokagero 27.10.2006, 17:19
Спасибо... Буду очень признателен. 

Автор: drkot 27.10.2006, 18:37
Вот накрапал.
Реализована односторонняя передача файлов.

PS: С тебя ящик пива.  smile 

Автор: Tokagero 28.10.2006, 09:05
По мойму эта программа для получателя... а НЕ для отправителя. Мне то и надобыло чтоб была прога серва, отправляющего опред. файл, например, с:\pic.jpg. Просто мне в 12.30 (украина,донецк) седня надо буде это показать... Можно реализовать??  smile 
Зы сервер отправляет, компы получают.

Автор: drkot 30.10.2006, 15:39
там две программы одна передает (та что с кнопкой), а вторая принимает (та что с memo).
если ты их обе откомпилировал и запустил то при нажатии на кнопку появится запрос на выбор файла. файл рассылается в пределах подсети.

Автор: drkot 30.10.2006, 16:03
Цитата(Tokagero @  28.10.2006,  09:05 Найти цитируемый пост)
Зы сервер отправляет, компы получают.

а сермер не комп типа?

соединение всегда инициирует клиент, сервер может только отвечает.

Автор: Rodman 4.11.2006, 16:55
drkot, а вот можно ли как нить эту картинку получить и прямо из потока вывести в Image... и так каждую секунду???

Автор: Tokagero 4.11.2006, 19:20
drkot, в том примере что ты дал сервер получает файлы... А клиент отправляет... А можно наоборот... Я могу выложить то что я навоял и сможешь подправить?? smile 

Автор: Rodman 4.11.2006, 23:50
Tokagero, а просто сервер подписать как клиент, а клиент как сервер...

Получателем сервер служит... тебе что важно как компоненты называются...

Автор: drkot 6.11.2006, 12:22
Цитата(Rodman @  4.11.2006,  16:55 Найти цитируемый пост)
потока вывести в Image... и так каждую секунду

Image.Picture.LoadFromStream();

Автор: Rodman 6.11.2006, 12:35
drkot, а вот к примеру в Stream можно сразу и сохранять, не сохраняя на винте???

Нет ли каких нить нюансов с этим???

Автор: Rodman 8.11.2006, 11:18
Вернее как картинку в Stream поместить??? smile 

Автор: drkot 8.11.2006, 11:23
Создать поток типа TmemorySteam
записать в него получаемые пакеты, а потом описанное ранее действие.
запись аналогична записи в файл

Автор: Tokagero 8.11.2006, 15:57
Image1.picture.SaveToStream()
<Посылка стрима на др комп>
Image1.picture.LoadFromStream

Автор: ruX 8.11.2006, 18:39
2 Stream:
На самом деле вот что:
  • Просто содержимое скриншоте передавать безполезно. Ибо наразрешении 1280х1024х32 будет файл почти 6 метров, если локалка 100мбит, то на передачу такого уйдёт целая секунда, при расчёта что больше никто ничего не передаёт
  • Можно жать jpeg-ом, тогда размер файла при максимально качестве будет в среднем 700кило, при среднем - 300. Но на сжатие скриншота жепегом уходит время, а главное не мало ресурсов процессора. опять же на 100мегабитах можно передать уже 10-12кадров(скриншотов smile в секунду
  • К сожалению пакеты UDP не фрагментируются, а размеры иизображений очень большие, поэтому приходиться пользоваться протоколом TCP, хотя это не оправданно
Я такую штуку делал. Раньше у мя была сеть 10мбит, удавалось передавать по 3-4 кадра в секунду, приэтом процессор был жутко занят(как на машине сервере, так и у клиента) Сейчас на 100мбит передаётсья по 10 кадров в сек.

Посмотри сколько трафа кушают такие проги как radmin.. Похоже что они передают клиенту только те участки экрана, которые изменились.

Автор: Rodman 8.11.2006, 18:51
ruX, ну мне необходи прога типа NetMeeting, RAdmin - слишком сложен для написания...

Если можешь кинь что писал...

Автор: drkot 9.11.2006, 14:06
Цитата(ruX @  8.11.2006,  18:39 Найти цитируемый пост)
К сожалению пакеты UDP не фрагментируются, а размеры иизображений очень большие, поэтому приходиться пользоваться протоколом TCP, хотя это не оправданно

вопервых чем плох udp? все реализуется наура. пример этого в топике.


Цитата(ruX @  8.11.2006,  18:39 Найти цитируемый пост)
Я такую штуку делал. Раньше у мя была сеть 10мбит, удавалось передавать по 3-4 кадра в секунду, приэтом процессор был жутко занят(как на машине сервере, так и у клиента) Сейчас на 100мбит передаётсья по 10 кадров в сек.

это смотря как делать (если попиксельно прорисовавать то да)

Цитата(ruX @  8.11.2006,  18:39 Найти цитируемый пост)
Похоже что они передают клиенту только те участки экрана, которые изменились.

Кто мешает такое реализовать?

Автор: Rodman 9.11.2006, 14:16
Ну я так понимаю, что лучше через TCP делать...

Тогда:
1. Возможно ли на нем послать широковещательный запрос???
2. С ним работать почти также как и с UDP???


Автор: Tokagero 9.11.2006, 20:13
Ой... Не надо ТСР... Я уже с УДП давно мучаюсь! Еще и с ТСП столько-же промучаться??

Автор: drkot 10.11.2006, 11:40
Цитата(Rodman @  9.11.2006,  14:16 Найти цитируемый пост)
Ну я так понимаю

Каждый протокол предназначен для решения своих задач и просто думать здесь мало.

Мне вобщем непонятно куда ползет топик.
Цитата(Tokagero @  25.10.2006,  18:07 Найти цитируемый пост)
Итак, идея в том чтоб сделать прогу, которая с определенного сервера локальной сети передавала картинки на несколько других компов в сети, причем без открывания локального доступа и т.д.

Вопрос давно решен.

Автор: ruX 10.11.2006, 13:04
Цитата(Rodman @ 8.11.2006,  18:51)
Если можешь кинь что писал...

Приведу только ключевые фрагменты кода:
(для сервера)
Код

var
  bmp : TImage;
  jpg : TJPEGImage;
// Глобальные объекты которые создаются и разрушаются с запуском и выгрузкой программы.

procedure SendFullScreen(Socket: TCustomWinSocket; q : integer);
var
    ms : TStringStream;
    ScreenDC : HDC;
    ib : tInteger2bytes;
begin
    ms := TStringStream.Create('S');//(Socket, 2000);


    bmp.Width:=screen.DesktopWidth;
    bmp.Height:=screen.DesktopHeight;
    ScreenDC:=GetDC(0);

    BitBlt(bmp.Canvas.Handle, 0,0, bmp.Width, bmp.Height,ScreenDC, 0, 0, SRCCOPY );

    ReleaseDC(0, ScreenDC);

    jpg.Assign(bmp.Picture.Graphic);
    jpg.CompressionQuality := q;
    jpg.ProgressiveEncoding := True;
    jpg.Compress;
    jpg.SaveToStream(ms);


    ib.int := length(ms.DataString);

    socket.SendText(ib.chrs[1]+ib.chrs[2]+ib.chrs[3]+ms.DataString);

    ms.Destroy;
end;


(для клиента)
Код

procedure TruAndminClientWindow.cSRead(Sender: TObject; Socket: TCustomWinSocket);
var
    s : string;
    ss : TstringStream;
    classMessege  : chaR;
    len : tInteger2bytes;
    t : cardinal;
begin
    if (socket.ReceiveLength = 0) then begin
            buf := '';    exit;
    end;

    s := buf + socket.ReceiveText;

    len.chrs[1] := s[1];
    len.chrs[2] := s[2];
    len.chrs[3] := s[3];

    s := copy(s, 4, length(s));
    if len.int > length(s)-3 then begin
        buf := len.chrs[1] + len.chrs[2] + len.chrs[3] + s;
        exit;
    end;

    buf := copy(s, len.int+1, length(s));
    s := copy(s, 1, len.int);

    ss := TstringStream.Create(s);
    s := '';
    image.Picture.Graphic.LoadFromStream(ss);
    reCalcKoofs;
    ss.Destroy;
end;

Вот.. Щас и сам вижу что многие вещи тупо сделал.


Цитата
Ой... Не надо ТСР... Я уже с УДП давно мучаюсь! Еще и с ТСП столько-же промучаться??

Ну не знаю чего там мучаться.. Единственное отличие явно видимое - это то  что соединение устанавливаеться, пакеты фрагментируются, в случае ошибки пакет будет заново послан, т.е. данные не потеряются.


Цитата
Ну я так понимаю, что лучше через TCP делать...

Тогда:
1. Возможно ли на нем послать широковещательный запрос???
2. С ним работать почти также как и с UDP???

1) нед
2) начни с компонентов, посмотри пример чата который с делфи идёт

Добавлено @ 13:07 
[

Добавлено @ 13:07 
[

Автор: Tokagero 10.11.2006, 20:31
ruX, а если надо сразу на несколько компов а широковещания нету тоо... С каждым связь чели устанавливать?? Или как?
TruAndminClientWindow.cSRead это в каком компоненте?? (на че жать?)

Автор: drkot 10.11.2006, 20:38
Цитата(Tokagero @  10.11.2006,  20:31 Найти цитируемый пост)
сразу на несколько компов

для этого и есть UDP. 
Можно конечно каналы организовать, но это сложнее.

Автор: ruX 1.12.2006, 11:13
Эм.
TruAndminClientWindow.cSRead  - это метод. Нинада ниначё жать smile 
Насколько я помню то это обработчик события проходящих в сокет данных.

А что касается множества компьютеров, то я согласен.

Автор: madi 23.11.2009, 09:18
Здравствуйте!!!
Помогите пожалуйста!!!! 
Как загрузить файл через сеть,  не открывая диалог

Автор: drkot 23.11.2009, 14:55
Забодай меня комар...

madi, книжку прочитай! или статьи коих в инете полно!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)