Конференция "WinAPI" » Выбор способа межпроцессного взаимодействия [D7, WinXP]
 
  • vlk32 (13.11.12 19:08) [0]
    В MSDN есть такой список вариантов взаимодействия между приложениями (процессами):

    The following IPC mechanisms are supported by Windows:

       Clipboard
       COM
       Data Copy
       DDE
       File Mapping
       Mailslots
       Pipes
       RPC
       Windows Sockets

    Кто может навскидку сказать что лучше выбрать с точки зрения скорости обмена данными с учетом того, что приложения могут взаимодействовать как в рамках одной машины так и на разных машинах (но в одной локальной сети).
  • brother © (13.11.12 19:21) [1]
    > что приложения могут взаимодействовать как в рамках одной
    > машины так и на разных машинах (но в одной локальной сети)
    > .


    > Windows Sockets
  • vlk32 (13.11.12 19:25) [2]

    > > Windows Sockets


    А трубы? Они вроде тоже могут по сети работать. Или они медленней получатся?
  • Rouse_ © (13.11.12 20:35) [3]
    В рамках локалки - сокеты, пайпы поверх них сидят, т.е. лишний траффик (если уж так сильно оптимизировать надо) + некоторые заморочки с безопасностью могут вылезти.
  • krupt © (08.12.12 00:51) [4]
    Rouse_, здраствуйте. Скачал ваш пример FWIOCompletionPipes. Там пример с передачей чисел. Че-то туплю и не могу сделать передачу текста(String, PChar и т.д.). Не подскажете, как это можно сделать? Спасибо.
  • Rouse_ © (08.12.12 01:01) [5]
    String, PChar и т.д. это указатели на данные.
    Стало быть, передавай их не их самих, а непосредственно то, на что они указывают.
  • DVM © (08.12.12 01:15) [6]

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

    пайпы значительно быстрее


    > так и на разных машинах

    сокеты быстрее
  • krupt © (10.12.12 20:59) [7]

    > String, PChar и т.д. это указатели на данные.
    > Стало быть, передавай их не их самих, а непосредственно
    > то, на что они указывают.


    Блин. Чего-то не получается у меня. Получаю EAccessViolation.
  • Cobalt © (10.12.12 22:09) [8]
    Не показывай код, дождись когда подтянутся телепаты.
  • krupt © (12.12.12 21:20) [9]
    Клиент:
    procedure TForm1.Button1Click(Sender: TObject);
    var
     InString, OutString: String;
     PipeClient: TFWPipeClient;
     InStream, OutStream: TMemoryStream;
    begin
     InString := Edit1.Text;
     try
       PipeClient := TFWPipeClient.Create('.', 'FWIOCompletionPipeServer');
       try
         PipeClient.Active := True;
         InStream := TMemoryStream.Create;
         try
           OutStream := TMemoryStream.Create;
           try
             InStream.Clear;
             InStream.WriteBuffer(Pointer(InString)^, Length(InString));
             PipeClient.SendData(InStream, OutStream);
           finally
             OutStream.Free;
           end;
         finally
           InStream.Free;
         end;
       finally
         PipeClient.Free;
       end;
     except
       on E:Exception do
         Memo1.Lines.Add(E.Classname + ': ' + E.Message);
     end;
    end;



    Сервер:
    procedure TSimpleObject.Read(Sender: TObject; PipeInstance: PFWPipeData);
    var
     InString: String;
    begin
     Move(PipeInstance^.ReadBuff[0], InString, PipeInstance^.ReadBuffSize);
     Form1.Memo1.Lines.Add('Str = ' + InString);
    end;

  • Германн © (12.12.12 21:40) [10]
    Навскидку
    SetLength(InString,PipeInstance^.ReadBuffSize);
    Move(PipeInstance^.ReadBuff[0], InString[1], PipeInstance^.ReadBuffSize);

  • Rouse_ © (12.12.12 22:18) [11]
    1. PipeClient.SendData - проверь, по памяти не помню, правит ли он позицию перед отправкой. Если нет, то выставляй ее в ноль перед вызовом
    2. Move(PipeInstance^.ReadBuff[0], InString, PipeInstance^.ReadBuffSize);
    Для начала желательно передавать размер строки и потом е саму, в противном случае поимееш проблем на склейке пакетов, ну есессно размер принимаещего буфера у тебя не выставлен, как и сказал Германн.
    3. тоже проверь, если принимающий буфер не требуется то и создавать OutStream не нужно

    ЗЫ: щас просто без кода сижу, поэтому по памяти все говорю...
  • krupt © (12.12.12 22:28) [12]
    Теперь AV нету, но принимает стоку коряво.

    Отправляю: "Edit1", получаю: "Edu".
    Отп.: "kak dela?", пол.: "kak dipe\"
  • krupt © (12.12.12 22:30) [13]
    procedure TFWPipeClient.SendData(InStream, OutStream: TStream);
    var
     lpBytesRead: DWORD;
    begin
     InStream.Position := 0;
     InStream.ReadBuffer(FBuff[0], InStream.Size);
     Win32Check(TransactNamedPipe(FPipe, @FBuff[0], InStream.Size,
       @FBuff[0], MAXWORD, lpBytesRead, nil));
     OutStream.Size := 0;
     OutStream.WriteBuffer(FBuff[0], lpBytesRead);
     OutStream.Position := 0;
    end;

  • Rouse_ © (12.12.12 22:44) [14]
    Скорее всего тут проблема:
    InStream.WriteBuffer(Pointer(InString)^, Length(InString));
    строки юникодные?
  • krupt © (12.12.12 23:37) [15]

    > Скорее всего тут проблема:
    > InStream.WriteBuffer(Pointer(InString)^, Length(InString));
    >
    > строки юникодные?


    InString := Edit1.Text;


    Вроде нет
  • Rouse_ © (12.12.12 23:39) [16]

    > Вроде нет

    Ну мы ж не бабки-гадалки, сделай все свои строки в виде AnsiString и проверь...
  • krupt © (12.12.12 23:47) [17]
    Добавил инфо:
    procedure TSimpleObject.Read(Sender: TObject; PipeInstance: PFWPipeData);
    var
     InString: String;
    begin
     WriteToFile('server.log', 'Length = ' + IntToStr(PipeInstance^.ReadBuffSize));
     SetLength(InString, PipeInstance^.ReadBuffSize);
     Move(PipeInstance^.ReadBuff[0], InString[1], PipeInstance^.ReadBuffSize);
    {  PipeInstance^.WriteBuff[0] := PipeInstance^.ReadBuff[0];
     PipeInstance^.WriteBuffSize := PipeInstance^.ReadBuffSize;}

     WriteToFile('server.log', 'Str = ' + InString);
    end;



    При получении "Edit1" в файле имеется:
    Length = 5
    Str = Ed???
  • krupt © (12.12.12 23:49) [18]
    После изменения String на AnsiString получаю:

    Length = 5
    Str = ?????
  • Германн © (13.12.12 00:20) [19]

    > krupt ©   (12.12.12 23:49) [18]
    >
    > После изменения String на AnsiString получаю:

    В клиенте тоже такую замену сделал?
  • krupt © (13.12.12 00:33) [20]
    Блин. В одном месте забыл поменять. Изменил. Теперь все ок.
    Только есть проблема с приёмом сообщения клиентом.
    procedure TForm1.Button1Click(Sender: TObject);
    var
     InString, OutString: AnsiString;
     PipeClient: TFWPipeClient;
     InStream, OutStream: TMemoryStream;
    begin
     InString := Edit1.Text;
     OutString := '';
     try
       PipeClient := TFWPipeClient.Create('.', 'FWIOCompletionPipeServer');
       try
         PipeClient.Active := True;
         InStream := TMemoryStream.Create;
         try
           OutStream := TMemoryStream.Create;
           try
             InStream.Clear;
             InStream.SetSize(Length(InString));
             Memo1.Lines.Add('OutStr = ' + InString);
             Data := Length(InString);
             Memo1.Lines.Add('OutStrLen = ' + IntToStr(Data));
             InStream.WriteBuffer(Pointer(InString)^, Length(InString));
             PipeClient.SendData(InStream, OutStream);
             SetLength(OutString, OutStream.Size);
             OutStream.ReadBuffer(Pointer(OutString)^, OutStream.Size);
             Memo1.Lines.Add('InStrLen = ' + IntToStr(OutStream.Size));
             Memo1.Lines.Add('InStr = ' + OutString);
           finally
             OutStream.Free;
           end;
         finally
           InStream.Free;
         end;
       finally
         PipeClient.Free;
       end;
     except
       on E:Exception do
         Memo1.Lines.Add(E.Classname + ': ' + E.Message);
     end;
    end;



    Получаю обратное на "Edit1":
    InStrLen = 5
    InStr = Ed
  • Германн © (13.12.12 00:53) [21]
    Где-то все-таки юникод остался. Скорее всего.
    В результате в какой-то функции приема/передачи принимается/передается вдвое меньше байт, чем следовало бы.
  • Германн © (13.12.12 01:26) [22]
    Вот что происходит когда строковый тип используется в качестве "простого буфера для функций приема/передачи"!
    Как хорошо всё выглядело когда тип String был простой "паскалевской" строкой. И как плохо с этим в Д2009+.
    Все "привычные" функции приема/передачи имеют параметр, который относится к количеству принятых/переданных байт. В то время как "длина" строки, которая определяется функцией Length и задаётся процедурой SetLength зависит от кодировки и не всегда равна количеству байт занимаемых строкой.
  • Anatoly Podgoretsky © (13.12.12 08:10) [23]
    > Германн  (13.12.2012 01:26:22)  [22]

    И разве это проблема
  • krupt © (13.12.12 11:38) [24]

    > 3. тоже проверь, если принимающий буфер не требуется то
    > и создавать OutStream не нужно

    А куда тогда результат то девать?
  • krupt © (13.12.12 12:59) [25]
    Что в этом случае передавать в качестве второго параметра? nil?
  • Rouse_ © (13.12.12 13:34) [26]
    Проверил - проблема была до кучи и в самом классе (буфера юникодные использовались).
    Забирай обновку, в качестве демки я туда как раз прикрутил передачу строк.
    http://rouse.drkb.ru/network.php#fwiocompletionpipe
  • Германн © (14.12.12 01:56) [27]

    > Rouse_ ©   (13.12.12 13:34) [26]
    >
    > Проверил - проблема была до кучи и в самом классе (буфера
    > юникодные использовались).

    Ну я ж говорил, что где-то все-таки юникод остался. :)
  • Германн © (14.12.12 02:04) [28]

    > Anatoly Podgoretsky ©   (13.12.12 08:10) [23]
    >
    > > Германн  (13.12.2012 01:26:22)  [22]
    >
    > И разве это проблема
    >

    Ну смотри. При переносе кода с 16-ти битной Дельфи на 32-х битную мне достаточно было лишь поставить в проекте опцию {$H-}  и всё работало.
    А вот при переносе с Д2007 на Д2009+ нужно сделать гораздо больше "телодвижений". И больше всего меня смущает то, что написано в доквики:
    In Delphi code, Length returns the number of characters actually used in the string or the number of elements in the array. In C++ code, use the method of the same name on the AnsiString or DynamicArray class.

    S is a string-valued or array-valued expression.

    For single-byte and multibyte strings, Length returns the number of bytes used by the string. Example for UTF-8:

    Writeln(Length(Utf8String('1¢'))); // displays 3

    For Unicode (WideString) strings, Length returns the number of bytes divided by two.
  • krupt © (14.12.12 21:20) [29]
    Спасибо. Разобрался со всем этим.
    Для использования с формами сделал наследника от TThread и переназначил метов Execute:
    procedure TMyThread.Execute;
    var
     PipeServer: TPipeServer;
    begin
     try
       PipeServer := TPipeServer.Create;
       try
         PipeServer.Server.Active := True;
       finally
         PipeServer.Free;
       end;
     except
     end;
    end;

  • krupt © (14.12.12 22:17) [30]
    Ах, да. Забыл. TPipeServer - это как TSimpleObject из примера :)
 
Конференция "WinAPI" » Выбор способа межпроцессного взаимодействия [D7, WinXP]
Есть новые Нет новых   [134430   +2][b:0.001][p:0.004]