如何用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
相关产品推荐
相关产品推荐

