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;
,如果我沒有記錯,你應該使用「直到CNT <1」,我看不出現在是什麼「ReceiveBuf」返回...... – ComputerSaysNo 2012-01-05 20:34:16
同意。 ReceiveBuf可能返回-1(SOCKET_ERROR) – 2012-01-05 21:00:48
ReceiveBuf()僅在Count = -1時返回0,並且沒有數據可用(由內部的ReceiveLength()使用),或者套接字斷開連接。如果套接字在非阻塞套接字上報告WSAEWOULDBLOCK錯誤,或者發生實際套接字錯誤並且分配的OnError事件句柄設置ErrorCode:0,則ReceiveBuf()返回-1。否則,'ReceiveBuf()'會引發一個'ESocketError'異常。 – 2012-01-05 21:16:41