gpt4 book ai didi

delphi - 通过套接字发送正确的记录大小

转载 作者:行者123 更新时间:2023-12-01 21:40:02 26 4
gpt4 key购买 nike

我有这个记录:

type
TSocks5_Packet = record
Socks_ID: String[6];
Socks_Packet: array of byte;
end;

我放置 String[6] 是因为我确信该字符串始终有 6 个字符(并尝试方便我的工作,但还不够)。

我尝试在此处发送此记录:

procedure TForm1.SocksServerClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Socks5_Request: TSocks5_Packet;
begin
SetLength(Socks5_Request.Socks_Packet, Socket.ReceiveLength);
Socket.ReceiveBuf(Socks5_Request.Socks_Packet[0], Length(Socks5_Request.Socks_Packet));
Socks5_Request.Socks_ID:= PSocket_Identity(Socket.Data).Sock_ID;
TunnelClient.SendBuf(Socks5_Request, Length(Socks5_Request.Socks_Packet + Length(Socks5_Request.Socks_ID)));
end;

我很确定问题出在 SendBuf 第二个参数上,我在其中指定要发送的字节数。正确的方法是什么?我应该如何学习?

最佳答案

您的代码存在几个问题:

  1. 您期望 String[6] 为 6 个字节,但实际上是 7 个字节。您正在声明一个最大长度为 6 个 AnsiChar 字符的 ShortString,并且 ShortString 包含长度的前导字节。

  2. 您的记录未打包,因此需要对齐填充。因此,不要尝试按原样发​​送。您正在处理可变长度数据,因此您应该序列化记录的内容。

  3. 字节数组是一个动态数组。动态数组是指向内存中其他位置分配的数据的指针。数组变量本身的字节大小为 SizeOf(Pointer),在 32 位上为 4,在 64 位上为 8。您必须取消引用指针才能访问分配的内存块。您在接收时执行此操作,但在发送时未执行此操作。

  4. TCP是一种流式传输,它根本没有消息的概念。 Socket.ReceiveLength 报告该特定时刻当前位于套接字内部接收缓冲区中的未读字节数。这些字节是任意的,缓冲区中可能只有 1 个字节。在查询长度之后、执行实际读取之前,可能会收到更多字节。

  5. 发送数据时,不保证发送您请求的字节数,可能会发送更少的字节。 SendBuf() 的返回值表示实际接受发送的字节数,因此您可能需要多次调用 SendBuf() 来发送特定的数据。因此循环发送直到数据耗尽。

  6. 由于您正在尝试隧道传输任意数据,因此您需要指定实际传输的字节数。

话虽如此,尝试更多类似这样的事情:

function TForm1.SendData(Socket: TCustomWinSocket; const Data; DataLen: Integer): Boolean;
var
PData: PByte;
NumSent: Integer;
begin
Result := False;
PData := PByte(@Data);
while DataLen > 0 do
begin
// SendBuf() returns -1 on error. If that error is WSAEWOULDBLOCK
// then retry the send again. Otherwise, TCustomWinSocket disconnects
// itself, and if its OnError event handler does not set the ErrorCode
// to 0 then it raises an ESocketError exception...
//
NumSent := Socket.SendBuf(PData^, DataLen);
if NumSent = -1 then
begin
if WSAGetLastError() <> WSAEWOULDBLOCK then
Exit;
end else
begin
Inc(PData, NumSent);
Dec(DataLen, NumSent);
end;
end;
Result := True;
end;

function TForm1.SendInteger(Socket: TCustomWinSocket; Value: Integer): Boolean;
begin
Value := htonl(Value);
Result := SendData(Socket, Value, SizeOf(Value));
end;

function TForm1.SendString(Socket: TCustomWinSocket; const Value: String): Boolean;
var
S: AnsiString; // or UTF8String
begin
S := AnsiString(Value);
// or: S := UTF8Encode(Value);
Result := SendInteger(Socket, Length(S));
if Result then
Result := SendData(Socket, PAnsiChar(S)^, Length(S));
end;

function TForm1.SendBytes(Socket: TCustomWinSocket; const Data: array of Byte): Boolean;
begin
Result := SendInteger(Socket, Length(Data));
if Result then
Result := SendData(Socket, PByte(Data)^, Length(Data));
end;

procedure TForm1.SocksServerClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
Packet: array of byte;
begin
Len := Socket.ReceiveLength;
if Len <= 0 the Exit;

SetLength(Packet, Len);
Len := Socket.ReceiveBuf(PByte(Packet)^, Len);
if Len <= 0 the Exit;
if Len < Length(Packet) then
SetLength(Packet, Len);

if SendString(TunnelClient, PSocket_Identity(Socket.Data).Sock_ID) then
SendBytes(TunnelClient, Packet);
end;

然后相应地调整隧道接收器以根据需要反序列化值(读取Integer字节计数,使用ntohl()将其转换为主机字节顺序,然后读取指定的字节数)。

关于delphi - 通过套接字发送正确的记录大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41131478/

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