- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
说到套接字,我最喜欢 TClientSocket 和 TServerSockets,因为它们的用法很简单。
我的任务很简单。我需要通过这 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;
阅读器中的循环不断重复,我不知道为什么。问题的根源可能是什么?
最佳答案
<小时/>
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;
关于delphi - 为什么 TCusomWinSocket.ReceiveBuf 不返回 0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8748741/
说到套接字,我最喜欢 TClientSocket 和 TServerSockets,因为它们的用法很简单。 我的任务很简单。我需要通过这 2 个组件发送一个文件(RAW),所以我有 2 个例程,如下所
我是一名优秀的程序员,十分优秀!