delphi – 为什么TCusomWinSocket.ReceiveBuf没有返回0?
发布时间:2020-12-15 09:28:01 所属栏目:大数据 来源:网络整理
导读:说到套接字,TClientSocket和TServerSockets是我最喜欢的,因为它们使用简单. 我的任务很简单.我需要通过这两个组件发送一个文件(RAW),所以我有两个例程,如下所示: procedure csRead(Sender: TObject; Socket: TCustomWinSocket);var MSCli : TMemoryStream;
说到套接字,TClientSocket和TServerSockets是我最喜欢的,因为它们使用简单.
我的任务很简单.我需要通过这两个组件发送一个文件(RAW),所以我有两个例程,如下所示: 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; 读者的循环是不知不觉地重复,我不知道为什么.可能是问题的根源是什么? 解决方法
SendStream()不是一个特别好的选择 – 永远.它旨在发送整个TStream,然后在完成后释放它.但是,如果套接字设置为非阻塞模式并且套接字在发送期间阻塞,则SendStream()立即退出并且不释放TStream.您必须再次调用SendStream()以继续从SendStream()停止的位置发送TStream.但是还有其他条件会导致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^,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.Size); end; begin ... MSSErv.LoadFromFile('some file'); MSServ.Position := 0; SendMemStreamToSocket(Socket,MSServ); ... end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |