SendStream()
उपयोग करने के लिए एक विशेष रूप से अच्छा विकल्प नहीं है। इसका उद्देश्य पूरे TStream
को भेजना है और फिर समाप्त होने पर इसे मुक्त करना है। हालांकि, यदि सॉकेट को गैर-अवरुद्ध करने के लिए सेट किया गया है और भेजने के दौरान सॉकेट ब्लॉक, SendStream()
तत्काल बाहर निकलता है और TStream
को मुक्त नहीं करता है। SendStream()
कहां से TStream
भेजना जारी रखने के लिए आपको SendStream()
पर कॉल करना होगा। लेकिन ऐसी अन्य स्थितियां हैं जो SendStream()
को TStream
से बाहर निकलने के लिए और TStream
मुक्त करने के लिए वास्तव में नहीं जानती हैं, इसलिए SendStream()
को उसी 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;
स्रोत
2012-01-05 21:32:56
अगर मैं गलत नहीं कर रहा हूँ आप का उपयोग करना चाहिए 'cnt <1 जब तक', मैं अभी क्या "ReceiveBuf" रिटर्न नहीं देख सकता ... – ComputerSaysNo
सहमत। ReceiveBuf एक -1 (SOCKET_ERROR) –
'ReceiveBuf()' केवल 0 रिटर्न 0 लौटा सकता है जब 'गणना = -1' और कोई डेटा उपलब्ध नहीं है (' प्राप्तकर्ता लम्बाई() 'आंतरिक रूप से उपयोग किया जाता है), या जब सॉकेट डिस्कनेक्ट हो जाता है। 'ReceiveBuf()' रिटर्न -1 यदि सॉकेट गैर-अवरुद्ध सॉकेट पर 'WSAEWOULDBLOCK' त्रुटि रिपोर्ट करता है, या वास्तविक सॉकेट त्रुटि होती है और एक असाइन किया गया' ऑनरर' ईवेंट हैंडलर 'त्रुटि कोड: = 0' सेट करता है। अन्यथा, 'ReceiveBuf() 'इसके बजाय' ESocketError 'अपवाद उठाएगा। –