You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Delphi单TServerSocket连接同时接收文本与图片?

单个Socket同时接收文本与图片的Delphi实现方案

核心思路

沿用你提供的C#方案的标记区分策略:用<|data|>标识文本数据,<|screen|>标识图片数据。在单个Socket连接的接收循环中,先缓存接收的字节数据,解析内容中的标记后,分别处理文本或图片逻辑。同时需处理网络通信常见的粘包问题,确保数据解析准确。

实现代码(基于Indy组件)

以下示例使用Delphi常用的Indy TIdTCPServer组件实现,代码包含完整的接收逻辑和事件回调:

unit SocketDataReceiver;

interface

uses
  IdTCPServer, IdContext, SysUtils, Classes, IdGlobal;

type
  // 文本接收事件
  TTextReceivedEvent = procedure(AContext: TIdContext; const AText: string) of object;
  // 图片接收事件
  TImageReceivedEvent = procedure(AContext: TIdContext; AImageBytes: TBytes) of object;

  TSocketDataHandler = class
  private
    FTextBuffer: string;
    FImageBuffer: TBytes;
    FOnTextReceived: TTextReceivedEvent;
    FOnImageReceived: TImageReceivedEvent;
    procedure ParseReceivedData(AContext: TIdContext; const ABuffer: TBytes);
  public
    procedure HandleClientExecute(AContext: TIdContext);
    property OnTextReceived: TTextReceivedEvent read FOnTextReceived write FOnTextReceived;
    property OnImageReceived: TImageReceivedEvent read FOnImageReceived write FOnImageReceived;
  end;

implementation

const
  MARKER_TEXT = '<|data|>';
  MARKER_IMAGE = '<|screen|>';

procedure TSocketDataHandler.ParseReceivedData(AContext: TIdContext; const ABuffer: TBytes);
var
  CurrentStr: string;
  TextMarkerPos, ImageMarkerPos: Integer;
  ImageDataStartIdx: Integer;
begin
  // 将接收的字节转为UTF-8字符串,用于标记检测
  CurrentStr := TIdTextEncoding.UTF8.GetString(ABuffer);
  FTextBuffer := FTextBuffer + CurrentStr;

  // 处理文本数据(循环检测,避免粘包导致多个文本标记)
  TextMarkerPos := Pos(MARKER_TEXT, FTextBuffer);
  while TextMarkerPos > 0 do
  begin
    // 提取标记后的文本内容
    if Length(FTextBuffer) > TextMarkerPos + Length(MARKER_TEXT) then
    begin
      if Assigned(FOnTextReceived) then
        FOnTextReceived(AContext, Copy(FTextBuffer, TextMarkerPos + Length(MARKER_TEXT), MaxInt));
    end;
    // 清除已处理的缓冲区内容
    Delete(FTextBuffer, 1, TextMarkerPos + Length(MARKER_TEXT) - 1);
    TextMarkerPos := Pos(MARKER_TEXT, FTextBuffer);
  end;

  // 处理图片数据
  ImageMarkerPos := Pos(MARKER_IMAGE, FTextBuffer);
  if ImageMarkerPos > 0 then
  begin
    // 合并缓存的文本字节与新接收的字节,提取图片数据部分
    ImageDataStartIdx := ImageMarkerPos + Length(MARKER_IMAGE);
    SetLength(FImageBuffer, Length(FImageBuffer) + Length(ABuffer));
    Move(ABuffer[0], FImageBuffer[Length(FImageBuffer) - Length(ABuffer)], Length(ABuffer));

    // 实际场景建议补充图片结束标记/长度校验,确保数据完整性
    if Assigned(FOnImageReceived) then
      FOnImageReceived(AContext, FImageBuffer);

    // 重置缓冲区
    FTextBuffer := '';
    SetLength(FImageBuffer, 0);
  end;
end;

procedure TSocketDataHandler.HandleClientExecute(AContext: TIdContext);
var
  RecvBuffer: TBytes;
  BytesRead: Integer;
begin
  SetLength(RecvBuffer, 1024); // 定义接收缓冲区大小
  BytesRead := AContext.Connection.IOHandler.ReadBytes(RecvBuffer, -1, False);
  if BytesRead > 0 then
  begin
    SetLength(RecvBuffer, BytesRead);
    ParseReceivedData(AContext, RecvBuffer);
  end;
end;

end.

调用示例(窗体中使用)

在Delphi窗体中放置TIdTCPServer组件,绑定事件实现业务逻辑:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  FDataHandler := TSocketDataHandler.Create;
  FDataHandler.OnTextReceived := OnTextReceived;
  FDataHandler.OnImageReceived := OnImageReceived;
  IdTCPServer1.OnExecute := FDataHandler.HandleClientExecute;
  IdTCPServer1.DefaultPort := 12345; // 设置监听端口
  IdTCPServer1.Active := True;
end;

procedure TMainForm.OnTextReceived(AContext: TIdContext; const AText: string);
begin
  // 线程安全更新UI,显示文本
  TThread.Synchronize(nil, procedure
  begin
    Memo_ReceivedText.Lines.Add('收到文本:' + AText);
  end);
end;

procedure TMainForm.OnImageReceived(AContext: TIdContext; AImageBytes: TBytes);
var
  MemStream: TMemoryStream;
  DisplayBitmap: TBitmap;
begin
  // 解析图片字节并显示
  MemStream := TMemoryStream.Create;
  DisplayBitmap := TBitmap.Create;
  try
    MemStream.WriteBuffer(AImageBytes[0], Length(AImageBytes));
    MemStream.Position := 0;
    DisplayBitmap.LoadFromStream(MemStream);
    TThread.Synchronize(nil, procedure
    begin
      Image_Display.Picture.Assign(DisplayBitmap);
    end);
  finally
    MemStream.Free;
    DisplayBitmap.Free;
  end;
end;

关键注意事项

  • 粘包处理:实际生产环境建议使用更严谨的协议,比如先发送数据类型+数据长度,再发送内容,避免标记被截断或粘包导致解析错误。
  • 编码一致性:确保Android端发送文本时使用UTF-8编码,与Delphi端解析逻辑匹配。
  • 图片完整性:Android端可先发送图片的字节长度,Delphi端根据长度接收完整的图片数据,避免图片截断。

内容的提问来源于stack exchange,提问作者FLASHCODER

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 03:31:04