在这种情况OnRead
下,读取套接字上当前可用的任何字节并将它们附加到缓冲区。然后,您可以遍历该缓冲区,仅提取完整的 XML 消息并根据需要对其进行处理,将不完整的 XML 消息留在缓冲区中,以便在以后的OnRead
事件中完成它们。
例如:
type
XmlHdr = packed record
Stx: Byte;
XmlLen: array[0..2] of Byte;
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
begin
// allocate the receive buffer
Socket.Data := TMemoryStream.Create;
end;
procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
// free the receive buffer
TMemoryStream(Socket.Data).Free;
Socket.Data := nil;
end;
procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
var
Strm: TMemoryStream;
RecvLen: Integer;
StrmSize: Int64;
Ptr: PByte;
hdr: XmlHdr;
xml: AnsiString;
begin
Strm := TMemoryStream(Socket.Data);
// check how many bytes are currently available on the socket
RecvLen := Socket.ReceiveLength;
if RecvLen <= 0 then Exit;
// read the bytes, appending them to the end of the buffer
StrmSize := Strm.Size;
Strm.Size := StrmSize + RecvLen;
Ptr := PByte(Strm.Memory);
Inc(Ptr, StrmSize);
RecvLen := Socket.ReceiveBuf(Ptr^, RecvLen);
if RecvLen <= 0 then
begin
Strm.Size := StrmSize;
Exit;
end;
Strm.Size := StrmSize + RecvLen;
// loop through the buffer processing only complete XML messages
Strm.Position := 0;
while (Strm.Size - Strm.Position) >= SizeOf(hdr) do
begin
// make sure the next byte starts a new header
Strm.ReadBuffer(hdr.Stx, 1);
if Hdr.Stx <> $2 then Continue;
// read the header's XML length
Strm.ReadBuffer(hdr.XmlLen[0], 3);
{
0 - Length, LSB
1 - Length
2 - Length, MSB
}
RecvLen := (Integer(hdr.XmlLen[2]) shl 16) or (Integer(hdr.XmlLen[1]) shl 8) or Integer(hdr.XmlLen[0]);
// check if the complete XML has been received
if (Strm.Size - Strm.Position) < RecvLen then
begin
// nope, keep waiting
Strm.Seek(-SizeOf(hdr), soCurrent);
Break;
end;
// extract the complete XML
SetLength(xml, RecvLen);
Strm.ReadBuffer(PAnsiChar(xml)^, RecvLen);
// process xml as needed...
end;
if strm.Position > 0 then
begin
// remove consumed bytes from the buffer and compact it
StrmSize := Strm.Size - Strm.Position;
if StrmSize = 0 then
begin
Strm.Clear;
end else
begin
Ptr := PByte(Strm.Memory);
Inc(Ptr, Strm.Position);
Move(Ptr^, Strm.Memory^, StrmSize);
Strm.Size := StrmSize;
end;
end;
end;