SendStream() 不是一个特别好的选择 - 永远。它旨在发送整个TStream,然后在完成后释放它。但是,如果套接字设置为非阻塞模式并且套接字在发送期间阻塞,SendStream() 将立即退出并且不会释放TStream。您必须再次致电SendStream() 才能继续从SendStream() 停止的位置发送TStream。但是还有其他情况会导致SendStream() 退出并释放TStream,而且你真的不知道它何时释放或没有释放TStream,因此尝试调用@987654331 变得非常危险@ 再次使用相同的 TStream 对象。更安全的方法是不惜一切代价避免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;