2012-01-05 29 views
5

जब सॉकेट की बात आती है, तो TClientSocket और TServerSockets उनके सरल उपयोग के कारण मेरी पसंदीदा हैं।क्यों TCusomWinSocket.ReceiveBuf कभी वापस नहीं आता है?

मेरा काम बहुत आसान है। मैं इन 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; 

रीडर में पाश है अंतहीन दोहराना और मुझे नहीं पता क्यों। समस्या का स्रोत क्या हो सकता है? कभी -

+3

अगर मैं गलत नहीं कर रहा हूँ आप का उपयोग करना चाहिए 'cnt <1 जब तक', मैं अभी क्या "ReceiveBuf" रिटर्न नहीं देख सकता ... – ComputerSaysNo

+1

सहमत। ReceiveBuf एक -1 (SOCKET_ERROR) –

+2

'ReceiveBuf()' केवल 0 रिटर्न 0 लौटा सकता है जब 'गणना = -1' और कोई डेटा उपलब्ध नहीं है (' प्राप्तकर्ता लम्बाई() 'आंतरिक रूप से उपयोग किया जाता है), या जब सॉकेट डिस्कनेक्ट हो जाता है। 'ReceiveBuf()' रिटर्न -1 यदि सॉकेट गैर-अवरुद्ध सॉकेट पर 'WSAEWOULDBLOCK' त्रुटि रिपोर्ट करता है, या वास्तविक सॉकेट त्रुटि होती है और एक असाइन किया गया' ऑनरर' ईवेंट हैंडलर 'त्रुटि कोड: = 0' सेट करता है। अन्यथा, 'ReceiveBuf() 'इसके बजाय' ESocketError 'अपवाद उठाएगा। –

उत्तर

5

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; 
संबंधित मुद्दे