gpt4 book ai didi

delphi - 通过套接字交换数据

转载 作者:行者123 更新时间:2023-12-02 07:52:19 24 4
gpt4 key购买 nike

当我向客户端发送字符串(tkString)时,客户端告诉我(在 WMClientRecv 内部)尝试重建 TValue 时出现访问冲突,为什么? -_-"与其他类型的数据一起工作得很好......

例如,整数(tkEnum)

这是服务器代码(将调用数据发送到客户端)

procedure TServerClass.InvokeMethod(const InvokableMethod: TInvokeableMethod; const MethodArg: TValue);
var
InvokeRec : packed record
Method: Array[0..19] of Char;
ArgRawSize: Integer;
ArgTypeInf: TTypeInfo;
ArgRawData: Array[0..255] of Byte;
end;
begin
// copy method name to record
lstrcpy(InvokeRec.Method, PChar(InvokableMethod));

// copy arg array to record
InvokeRec.ArgRawSize := MethodArg.DataSize;

if (MethodArg.DataSize <> 0) then
begin
MethodArg.ExtractRawData(PByte(@InvokeRec.ArgRawData[0]));

InvokeRec.ArgTypeInf := MethodArg.TypeInfo^;
end;

// send record
ServerSocket.Socket.Connections[idxSocket].SendBuf(PByte(@InvokeRec)^, SizeOf(InvokeRec));
end;

客户端将其读取为:

procedure TClientClass.ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
var
Buffer: PByte;
BufLen: Integer;

InvokeRec: TInvokeRec;
begin
BufLen := Socket.ReceiveLength;

Memo1.Lines.Append(Format('%d: Received %d bytes', [Memo1.Lines.Count, BufLen]));

// dump keep-alive from recv buffer
if (BufLen = 64) then
begin
GetMem(Buffer, BufLen);
try
Socket.ReceiveBuf(Buffer^, BufLen);
finally
FreeMem(Buffer, BufLen);
end;
Exit;
end;

Socket.ReceiveBuf(PByte(@InvokeRec)^, BufLen);
SendMessage(Handle, WM_ClientRecv, 0, LPARAM(@InvokeRec));
end;

WMClientRecv 例程:

procedure TClientClass.WMClientRecv(var Msg: TMessage);
var
// we send to server
ReadRec: TSharedRec;

// we recv from server
InvokeRecPtr: PInvokeRec;

Value: TValue;
begin
InvokeRecPtr := PInvokeRec(Msg.LParam);

case InvokeRecPtr.ArgRawSize of
0:
Value.Empty;
else
TValue.Make(PByte(@InvokeRecPtr.ArgRawData)^, PTypeInfo(@InvokeRecPtr.ArgTypeInf), Value);
end;

InvokableSubclass.ExecMethod(InvokeRecPtr.Method, Value);
end;

和ExceMethod:

procedure TInvokableSubclass.ExecMethod(const vmName: string; const Arg0: TValue);
var
LContext: TRttiContext;
begin
//
FSendMode := TextMode;

//
if (Arg0.DataSize = 0) then
begin
LContext.GetType(TInvokableSubclass).GetMethod(vmName).Invoke(Self, []);
Exit;
end;

LContext.GetType(TInvokableSubclass).GetMethod(vmName).Invoke(Self, Arg0);
end;

最佳答案

您正在尝试序列化 TTypeInfo 类型的变量。看一下它的声明:

TTypeInfo = record
Kind: TTypeKind;
Name: ShortString;
{TypeData: TTypeData}
end;

您的代码将序列化前两个字段,但无法序列化属于实现细节的隐藏字段。这是一个比较特殊的类型。您不能简单地将一个 TTypeInfo 变量分配给另一个变量。您应该传递 PTypeInfo 变量。

事实上,考虑发送类型信息的代码:

InvokeRec.ArgTypeInf := MethodArg.TypeInfo^;

这段代码已经被破坏了,因为它正在分配给一个TTypeInfo,正如我上面所说的,这不能通过简单的分配来完成。

现在,您显然无法简单地序列化 PTypeInfo,因为它仅在拥有它的进程的地址空间中有意义。并且您无法轻松调用 GetTypeData() 并序列化返回的 PTypeData。这是一个复杂的结构,还包含难以序列化的指针。

我怀疑最简单的方法是推出您自己的类型信息序列化机制。也许发送类型的名称就足够了,然后让接收者使用该名称查找它。

关于delphi - 通过套接字交换数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13360857/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com