SendStream()
не очень хороший выбор для использования - НИКОГДА. Он предназначен для отправки всего TStream
, а затем освободить его, когда закончите. Однако, если сокет установлен в неблокирующий режим и сокет блокируется во время отправки, SendStream()
немедленно завершается и НЕ освобождает TStream
. Вам нужно снова позвонить SendStream()
, чтобы продолжить отправку TStream
с того места, где остановился SendStream()
. Но есть и другие условия, которые могут заставить SendStream()
выйти и освободить TStream
, и вы не знаете, когда он освободил или не освободил TStream
, поэтому попытка вызвать * 1012 становится очень опасной. * снова с тем же 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;