Заметки · 13.06.2025

Кириллица в байтах

Не секрет, что при передаче кириллицы от клиента к серверу (и наоборот, кстати, тоже) с помощью компонентов TIdTCPServer (можно найти на вкладке Indy Servers — Core) и TIdTCPClient (вкладка Indy Clients — Core) библиотеки Indy10 в IDE Lazarus, вместо букв приходят вопросительные знаки.

Это лёгкое недоразумение можно исправить сконвертировав строку в массив байт при отправке и провести обратное преобразование при приёме. Никаких дополнительных модулей подключать не нужно. Всё можно осуществить с помощью функционала библиотеки Indy10.

Приведу пример кода серверной и клиентских частей. Сервер прослушивает порт 12345 и ждёт сообщения от клиента, а как только принимает сообщение — отправляет сообщение сам.

Код серверной части:

unit server_unit;

{$mode objfpc}{$H+}

interface

uses
  Classes, 
  SysUtils, 
  Forms, 
  Controls, 
  Graphics,
  IdTCPServer,
  IdContext,
  IdCustomTCPServer,
  IdGlobal,
  Dialogs;

type

  { TForm1 }

  TForm1 = class(TForm)

    // Объекты
    tcpserver: TIdTCPServer;

    // Процедуры
    procedure FormCreate(Sender: TObject);
    procedure tcpserverExecute(AContext: TIdContext);

  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

// Создание формы
procedure TForm1.FormCreate(Sender: TObject);
begin
  tcpserver.DefaultPort:=12345;
  tcpserver.Active:=True;
end;

// Процедура выполнения службы сервера
procedure TForm1.tcpserverExecute(AContext: TIdContext);
var
  ByteArrayIn: TIdBytes;
  ByteArrayOut: TIdBytes;
  ReceivedStr: string;
const
  sendtext='Сообщение успешно получено!';
begin
  // Принять данные от клиента
  AContext.Connection.IOHandler.ReadBytes(ByteArrayIn, -1, False);
  ReceivedStr:=BytesToString(ByteArrayIn);
  ShowMessage(ReceivedStr);
  // Отправить данные клиенту
  ByteArrayOut:=ToBytes(sendtext, IndyTextEncoding_UTF8);
  AContext.Connection.IOHandler.Write(ByteArrayOut, Length(ByteArrayOut));
end;

end.

Код клиентской части:

unit client_unit;

{$mode objfpc}{$H+}

interface

uses
  Classes, 
  SysUtils, 
  Forms, 
  Controls, 
  Graphics, 
  Dialogs,
  StdCtrls,
  IdGlobal,
  IdTCPClient;

type

  { TForm1 }

  TForm1 = class(TForm)

    // Объекты
    Button1: TButton;
    tcpclient: TIdTCPClient;

    // Процедуры
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);

  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

// Создание формы
procedure TForm1.FormCreate(Sender: TObject);
begin
  tcpclient.Host:='localhost';
  tcpclient.Port:=12345;
end;

// Нажатие на кнопку
procedure TForm1.Button1Click(Sender: TObject);
var
  ByteArrayOut: TIdBytes;
  ByteArrayIn: TIdBytes;
  ReceivedStr: string;
const
  sendtext='Всем привет!';
begin
  // Подключаемся к серверу
  tcpclient.Connect;
  // Отправляем данные
  ByteArrayOut:=ToBytes(sendtext, IndyTextEncoding_UTF8);
  tcpclient.IOHandler.Write(ByteArrayOut);
  // Принимаем данные об успешной доставке
  tcpclient.IOHandler.ReadBytes(ByteArrayIn, -1, False);
  ReceivedStr:=BytesToString(ByteArrayIn);
  ShowMessage(ReceivedStr);
  // Отключаемся от сервера
  tcpclient.Disconnect;
end;

end.

В коде нет обработки ошибок. Предполагается, что на момент запуска клиентского приложения — сервер уже запущен и нет никаких проблем с доступностью порта.

В качестве IP адреса я использовал localhost.