gpt4 book ai didi

delphi - 为什么 TCusomWinSocket.ReceiveBuf 不返回 0?

转载 作者:行者123 更新时间:2023-12-03 15:11:59 29 4
gpt4 key购买 nike

说到套接字,我最喜欢 TClientSocket 和 TServerSockets,因为它们的用法很简单。

我的任务很简单。我需要通过这 2 个组件发送一个文件(RAW),所以我有 2 个例程,如下所示:

procedure csRead(Sender: TObject; Socket: TCustomWinSocket);
var
MSCli : TMemoryStream;
cnt : Integer;
buf : array [0..1023] of byte;
begin
MSCli := TMemoryStream.Create;
try
repeat
cnt := Socket.ReceiveBuf(buf[0], 1024); //This loop repeats endlesly
MSCli.Write(buf[0], cnt)
until cnt = 0;
finally
MSCli.SaveToFile('somefile.dmp');
MSCli.Free;
end;
end;

当然还有发件人:

  //...some code
MSSErv.LoadFromFile('some file');
MSServ.Position := 0;
Socket.SendStream(MSServ);
end;

阅读器中的循环不断重复,我不知道为什么。问题的根源可能是什么?

最佳答案

<小时/>

SendStream() 从来都不是一个特别好的选择。它的目的是发送整个TStream,然后在完成后释放它。但是,如果套接字设置为非阻塞模式并且套接字在发送期间阻塞,则 SendStream() 会立即退出并且不会释放 TStream。您必须再次调用 SendStream() 才能从 SendStream() 中断处继续发送 TStream。但还有其他条件可能导致 SendStream() 退出并释放 TStream,并且您并不真正知道它何时释放或没有释放 TStream,因此尝试使用相同的 TStream 对象再次调用 SendStream() 变得非常危险。更安全的方法是不惜一切代价避免 SendStream() 并直接在您自己的循环中调用 SendBuf()

话虽如此,SendStream() 不会通知接收方将发送多少字节,因此接收方不知道何时停止读取(除非您在发送 后关闭连接>TStream)。更好的选择是先发送预期的字节数,然后再发送 TStream 数据。这样,接收方可以先读取字节数,然后在接收到指定字节数时停止读取。例如:

procedure ReadRawFromSocket(Socket: TCustomWinSocket; Buffer: Pointer; BufSize: Integer);
var
buf: PByte;
cnt: Integer;
begin
buf := PByte(Buffer);
while BufSize > 0 do
begin
cnt := Socket.ReceiveBuf(buf^, BufSize);
if cnt < 1 then begin
if (cnt = -1) and (WSAGetLastError() = WSAEWOULDBLOCK) then
begin
Application.ProcessMessages;
Continue;
end;
Abort;
end;
Inc(buf, cnt);
Dec(BufSize, cnt);
end;
end;

function ReadInt64FromSocket(Socket: TCustomWinSocket): Int64;
begin
ReadRawFromSocket(Socket, @Result, SizeOf(Int64));
end;

procedure ReadMemStreamFromSocket(Socket: TCustomWinSocket: Stream: TMemoryStream);
var
cnt: Int64;
begin
cnt := ReadInt64FromSocket(Socket);
if cnt > 0 then
begin
Stream.Size := cnt;
ReadRawFromSocket(Socket, Stream.Memory, cnt);
end;
end;

procedure csRead(Sender: TObject; Socket: TCustomWinSocket);
var
MSCli : TMemoryStream;
begin
MSCli := TMemoryStream.Create;
try
ReadMemStreamFromSocket(Socket, MSCli);
MSCli.SaveToFile('somefile.dmp');
finally
MSCli.Free;
end;
end;

procedure SendRawToSocket(Socket: TCustomWinSocket; Buffer: Pointer; BufSize: Integer);
var
buf: PByte;
cnt: Integer;
begin
buf := PByte(Buffer);
while BufSize > 0 do
begin
cnt := Socket.SendBuf(buf^, BufSize);
if cnt < 1 then begin
if (cnt = -1) and (WSAGetLastError() = WSAEWOULDBLOCK) then
begin
Application.ProcessMessages;
Continue;
end;
Abort;
end;
Inc(buf, cnt);
Dec(BufSize, cnt);
end;
end;

procedure SendInt64ToSocket(Socket: TCustomWinSocket; Value: Int64);
begin
SendRawToSocket(Socket, @Value, SizeOf(Int64));
end;

procedure SendMemStreamToSocket(Socket: TCustomWinSocket: Stream: TMemoryStream);
begin
SendInt64FromSocket(Socket, Stream.Size);
SendRawToSocket(Socket, Stream.Memory, Stream.Size);
end;

begin
...
MSSErv.LoadFromFile('some file');
MSServ.Position := 0;
SendMemStreamToSocket(Socket, MSServ);
...
end;

关于delphi - 为什么 TCusomWinSocket.ReceiveBuf 不返回 0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8748741/

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