delci memcached клиент для linux memcached сервер, работающий в windows 32, а не в linux, проблема кодирования, я думаю - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть это консольное приложение TEST, созданное в delphi 10.3.2.

Я могу обновить сервер memcached, работающий в "ubuntu linux", из него из приложения win32, если я скомпилирую это консольное приложение и запуском его наLinux это не будет работать.

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

program ProjecttestLinuxMemCach;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, system.json,system.netencoding,system.DateUtils,
  idtcpclient,idGlobal;

var
   tcp : TIdTCPClient;
   s   : String;

begin
  try
    tcp := TIdTCPClient.Create;
    try
      tcp.ConnectTimeout :=    1000;
      tcp.ReadTimeout    :=    3000;
      tcp.Host := '192.168.30.141';  // my local memcached server running on linux.
      tcp.Port := 11211;
      tcp.ReuseSocket := rsTrue;
      s:='set q 0 0 1'+sLineBreak+'b'+sLineBreak;
      tcp.Connect;
       tcp.Socket.Write(s);
       repeat
        s:=  tcp.Socket.ReadLn(sLineBreak);
       until (s = 'END')or (  s='' ) or (  s='STORED' );
       writeln(s)
    finally
      tcp.Free;
    end;

     readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Я попытался изменить sLineBreak на # 10 для Linux такой же проблемы. Когда я работаю в Linux, я получаю пустой ответ и значение не устанавливается.

Есть идеи, как это исправить?

Спасибо

1 Ответ

3 голосов
/ 05 ноября 2019

Константа RTL sLineBreak равна CRLF (#13#10) в Windows, но только LF (#10) в Linux.

Согласно спецификации Memcached :

В протоколе memcache отправляются два вида данных: текстовые строки и неструктурированные данные. Текстовые строки используются для команд от клиентов и ответов от серверов. Неструктурированные данные отправляются, когда клиент хочет сохранить или получить данные. Сервер будет передавать обратно неструктурированные данные точно так же, как он их получил, как поток байтов. Сервер не заботится о проблемах порядка байтов в неструктурированных данных и не знает о них. Нет ограничений на символы, которые могут появляться в неструктурированных данных;однако читатель таких данных (клиент или сервер) всегда будет знать из предыдущей текстовой строки точную длину передаваемого блока данных.

Текстовые строки всегда заканчиваются на \ r \ n . Неструктурированные данные также оканчиваются на \ r \ n, хотя внутри данных также могут появляться \ r, \ n или любые другие 8-битные символы. Поэтому, когда клиент получает данные с сервера, он должен использовать длину блока данных (с которым он будет предоставлен), чтобы определить, где заканчивается блок данных, а не тот факт, что \ r \ n следует за концомБлок данных, даже если это так.

Indy's IOHandler имеет метод WriteLn(), который отправляет константу IdGlobal.EOL (она же CRLF) на всех платформах. И IOHandler.ReadLn() по умолчанию обрабатывает оба терминатора CRLF и LF на всех платформах, если вы явно не указали свой собственный терминатор.

Для согласованности работы на всех платформах я предлагаю вам удалить всеиспользуйте sLineBreak из вашего кода TCP и позвольте Indy обрабатывать разрывы строк для вас, например:

program ProjecttestLinuxMemCach;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.JSON, System.NetEncoding, System.DateUtils,
  IdTCPClient, IdGlobal;

var
  tcp : TIdTCPClient;
  s   : String;
begin
  try
    tcp := TIdTCPClient.Create;
    try
      tcp.ConnectTimeout :=    1000;
      tcp.ReadTimeout    :=    3000;
      tcp.Host := '192.168.30.141';  // my local memcached server running on linux.
      tcp.Port := 11211;
      tcp.ReuseSocket := rsTrue;
      tcp.Connect;
      try
        tcp.Socket.WriteLn('set q 0 0 1');
        tcp.Socket.WriteLn('b');
        repeat
          s := tcp.Socket.ReadLn;
        until (s = 'END') or (s = '' {and not tcp.Socket.ReadLnTimedOut}) or (s = 'STORED');
        Writeln(s);
      finally
        tcp.Disconnect;
      end;
    finally
      tcp.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
...