当我调用TTcpClient.SendStream(MyStream)时,它将MyStream.Position提升到8704,并且我必须反复调用SendStream()以使其完全发送我的流。但是,收到的数据大约每8K丢失512字节的块。
注意:这个问题很有说服力,因为我经历了尝试并且未能在网上找到解决方案。我在Delphi 7 Sockets.pas中发现了这个错误,并希望为社区的利益发布解决方案。
答案 0 :(得分:2)
问题是Delphi 7 Sockets.pas中的编码错误。该错误导致任何大于约8K的流(确切大小取决于操作系统)丢失512字节的数据块。 SendStream实现使用repeat..until循环从调用者的流中提取512字节的缓冲区,以便使用SendBuf()进行发送,只要流有数据并且SendBuf()不返回等于SOCKET_ERROR。当Windows套接字缓冲区填满时会发生丢失,导致SendBuf()返回等于SOCKET_ERROR,但此时已经从调用者的流中读取了多达512个字节,并且流位置已经提前 - 但是退出时不会恢复位置。原始Sockets.pas代码:
function TBaseSocket.SendStream(AStream: TStream): Integer; var BufLen : Integer; Buffer: array[0..511] of Byte; begin Result := 0; if Assigned(AStream) then begin repeat BufLen := AStream.Read(Buffer, SizeOf(Buffer)); until (BufLen = 0) or (SendBuf(Buffer, BufLen) = SOCKET_ERROR); end; end;
这是一个解决方法:
function TBaseSocket.SendStream(AStream: TStream): Integer; var Quit : boolean; BufLen,OldPosition : Integer; Buffer: array[0..511] of Byte; begin Result := 0; if Assigned(AStream) then begin repeat OldPosition := AStream.Position; BufLen := AStream.Read(Buffer, SizeOf(Buffer)); if (BufLen > 0) then begin Quit := (SendBuf(Buffer, BufLen) = SOCKET_ERROR); if Quit then AStream.Position := OldPosition; //restore! end else begin //BufLen = 0 Quit := true; end; until Quit; end; end;