Delphi Indy10、iDTCPServer和idTCPClient的数据丢失
我有两个使用Delphy 10.3和Indy 10 idTCPServer和idTCPClient0的程序: 服务器端:Delphi Indy10、iDTCPServer和idTCPClient的数据丢失,delphi,buffer,tcpclient,indy,tcpserver,Delphi,Buffer,Tcpclient,Indy,Tcpserver,我有两个使用Delphy 10.3和Indy 10 idTCPServer和idTCPClient0的程序: 服务器端: 服务器使用计时器定期发送1个字节的数据集(150字节的数据) 服务器发送一个2个字节的数据集,但只是偶尔发送 服务器使用TIDServer.Connection.IOHandler.Write(IDBytesArray)发送数据 客户端: 客户端通过一个线程接收TIDBytes,如许多示例中所述 问题 如果服务器的计时器确实以低频率(1000毫秒)发送数据,则一切正
- 服务器使用计时器定期发送1个字节的数据集(150字节的数据)
- 服务器发送一个2个字节的数据集,但只是偶尔发送
- 服务器使用TIDServer.Connection.IOHandler.Write(IDBytesArray)发送数据李>
- 客户端通过一个线程接收TIDBytes,如许多示例中所述
- 如果服务器的计时器确实以低频率(1000毫秒)发送数据,则一切正常,客户端接收两个数据集(一个来自服务器的计时器,另一个频繁发送)李>
- 但是,如果服务器的计时器以高频(每50毫秒)发送数据集1,则无法接收来自第二个数据集的所有数据(但正在接收计时器发送的所有数据)李>
-这可能是缓冲区问题吗?或者计时器是否覆盖已在缓冲区中但客户端尚未读取的数据集2?我想知道有什么办法可以克服这种情况吗?勒博非常感谢您的回复。我认为您正确地提到了计时器可以将数据发送到端口,这可能会弄乱另一个计时器,该计时器同时也会将数据写入端口。 因此,我简化了示例:
- 客户机定期将数据1结构的记录以tidBytes的形式发送到服务器李>
- 服务器以确认响应李>
- 客户端检查确认是否属于上次发送的数据集。 只要客户端发送tha包的速度不超过每100毫秒一次,这就可以正常工作。如果发送速度为10毫秒,则客户端会丢失一些确认信息。 如果有帮助,我可以分享整个演示项目。但可能这不是stackoverflow的目的。因此,我在下面添加了一些代码:
type
TData1 = record // 11 bytes record
{header:}
MessageStart : Array[1..4] of Char; // 0
MessageID : word; // 4
{content:}
TransactionNo : Integer; // 6
TrackerMsgID : byte; // 10
end;
type
TAcknowledgeData1 = record // 14 bytes record
{Header:}
MessageStart : Array[1..4] of Char; // 0
MessageID : Word; // 4
{content:}
TransactionNo : Integer; // 6
EventID : Integer; // 10
end;
客户端有一个计时器,它定期向调用SendData1过程的服务器发送数据集1:
procedure TForm1.TimerClientTimer(Sender: TObject);
begin
SendData1(TransactionNr);
TransactionNr := TransactionNr + 1;
end;
procedure TForm1.SendData1 (Transaction: Integer);
var Data1 : TData1;
Data1Array : TIDBytes;
begin
{fill the data1 record:}
Data1.MessageStart := '$MSG'; //4 bytes
Data1.MessageID := 1; //2 bytes
Data1.TransactionNo:= Transaction; //4 bytes
Data1.TrackerMsgID := 1; //1 byte
{set the length of idBytes to get the dta 1 record:}
setLength (Data1Array,11);
{move data1 record to idBytes array:}
Move (Data1.MessageStart[1],Data1Array[0],1);
Move (Data1.MessageStart[2],Data1Array[1],1);
Move (Data1.MessageStart[3],Data1Array[2],1);
Move (Data1.MessageStart[4],Data1Array[3],1);
Move(Data1.MessageID, Data1Array[4],sizeOf(Word));
Move(Data1.TransactionNo,Data1Array[6],sizeOf(Integer));
Move(Data1.TrackerMsgID, Data1Array[10],sizeOf(Byte));
try
TCPClient.IOHandler.Write(Data1Array);
if chkData.checked then MemoClient.Lines.Add('Client sent Data1:'+inttostr(Data1.TransactionNo));
except
on E: Exception do
begin {nothing}
if chkData.checked then MemoClient.Lines.Add('Exception occured');
end;
end;
end;
当确认数据包从服务器到达时,客户端的工作线程正在调用DataReceived:
procedure TForm1.TimerClientTimer(Sender: TObject);
begin
SendData1(TransactionNr);
TransactionNr := TransactionNr + 1;
end;
procedure TForm1.SendData1 (Transaction: Integer);
var Data1 : TData1;
Data1Array : TIDBytes;
begin
{fill the data1 record:}
Data1.MessageStart := '$MSG'; //4 bytes
Data1.MessageID := 1; //2 bytes
Data1.TransactionNo:= Transaction; //4 bytes
Data1.TrackerMsgID := 1; //1 byte
{set the length of idBytes to get the dta 1 record:}
setLength (Data1Array,11);
{move data1 record to idBytes array:}
Move (Data1.MessageStart[1],Data1Array[0],1);
Move (Data1.MessageStart[2],Data1Array[1],1);
Move (Data1.MessageStart[3],Data1Array[2],1);
Move (Data1.MessageStart[4],Data1Array[3],1);
Move(Data1.MessageID, Data1Array[4],sizeOf(Word));
Move(Data1.TransactionNo,Data1Array[6],sizeOf(Integer));
Move(Data1.TrackerMsgID, Data1Array[10],sizeOf(Byte));
try
TCPClient.IOHandler.Write(Data1Array);
if chkData.checked then MemoClient.Lines.Add('Client sent Data1:'+inttostr(Data1.TransactionNo));
except
on E: Exception do
begin {nothing}
if chkData.checked then MemoClient.Lines.Add('Exception occured');
end;
end;
end;
procedure TForm1.Datareceived (Data : TidBytes);
var
MsgStart : array[1..4] of char;
s : string;
id : word;
Data1: TData1;
Data2: TData2;
Ack : TAcknowledgeData1;
AckArray: TidBytes;
begin
{get the header:}
s := bytestostring(Data,0,4);
if s = '' then exit;
move (Data[4],id,sizeof(word));
if (s = '$MSG') then
begin
if (ID=3) then
begin
move(Data[0],Ack.MessageStart,0);
Ack.MessageID := id;
Move (Data[6],Ack.TransactionNo,SizeOf(Word));
Move (Data[10],Ack.EventID,SizeOf(Integer));
LastAck := Ack.TransactionNo;
end;
end;
end;
当数据包从服务器到达时,客户端的工作线程正在调用DataReceived:
procedure TForm1.TimerClientTimer(Sender: TObject);
begin
SendData1(TransactionNr);
TransactionNr := TransactionNr + 1;
end;
procedure TForm1.SendData1 (Transaction: Integer);
var Data1 : TData1;
Data1Array : TIDBytes;
begin
{fill the data1 record:}
Data1.MessageStart := '$MSG'; //4 bytes
Data1.MessageID := 1; //2 bytes
Data1.TransactionNo:= Transaction; //4 bytes
Data1.TrackerMsgID := 1; //1 byte
{set the length of idBytes to get the dta 1 record:}
setLength (Data1Array,11);
{move data1 record to idBytes array:}
Move (Data1.MessageStart[1],Data1Array[0],1);
Move (Data1.MessageStart[2],Data1Array[1],1);
Move (Data1.MessageStart[3],Data1Array[2],1);
Move (Data1.MessageStart[4],Data1Array[3],1);
Move(Data1.MessageID, Data1Array[4],sizeOf(Word));
Move(Data1.TransactionNo,Data1Array[6],sizeOf(Integer));
Move(Data1.TrackerMsgID, Data1Array[10],sizeOf(Byte));
try
TCPClient.IOHandler.Write(Data1Array);
if chkData.checked then MemoClient.Lines.Add('Client sent Data1:'+inttostr(Data1.TransactionNo));
except
on E: Exception do
begin {nothing}
if chkData.checked then MemoClient.Lines.Add('Exception occured');
end;
end;
end;
procedure TForm1.Datareceived (Data : TidBytes);
var
MsgStart : array[1..4] of char;
s : string;
id : word;
Data1: TData1;
Data2: TData2;
Ack : TAcknowledgeData1;
AckArray: TidBytes;
begin
{get the header:}
s := bytestostring(Data,0,4);
if s = '' then exit;
move (Data[4],id,sizeof(word));
if (s = '$MSG') then
begin
if (ID=3) then
begin
move(Data[0],Ack.MessageStart,0);
Ack.MessageID := id;
Move (Data[6],Ack.TransactionNo,SizeOf(Word));
Move (Data[10],Ack.EventID,SizeOf(Integer));
LastAck := Ack.TransactionNo;
end;
end;
end;
一旦客户端发送了Data1包,服务器就会调用过程DataReceved。服务器将应答包发送回客户端:
procedure TForm1.Datareceived (Data : TidBytes);
var
MsgStart : array[1..4] of char;
s : string;
id : word;
Data1: TData1;
Data2: TData2;
Ack : TAcknowledgeData1;
AckArray: TidBytes;
begin
{get the header:}
s := bytestostring(Data,0,4);
if s = '' then exit;
move (Data[4],id,sizeof(word));
if (s = '$MSG') then
begin
{Server received Data1:}
if (ID=1) then
begin
{get data1:}
move(Data[0],Data1.MessageStart,0);
Data1.MessageID := id;
move (Data[6],Data1.TransactionNo,sizeOf(Integer));
move (Data[10],Data1.TrackerMsgID,sizeOf(Byte));
{send Acknowledge to client}
Ack.MessageStart := '$MSG';
Ack.MessageID := 3;
Ack.TransactionNo:= Data1.TransactionNo;
Ack.EventID := LastEventID;
LastEventID := LastEventID + 1;
SetLength(AckArray,14);
Move (Ack.MessageStart[1],AckArray[0],1);
Move (Ack.MessageStart[2],AckArray[1],1);
Move (Ack.MessageStart[3],AckArray[2],1);
Move (Ack.MessageStart[4],AckArray[3],1);
Move (Ack.MessageID,AckArray[4],sizeOf(Word));
Move (Ack.TransactionNo,AckArray[6],sizeOf(Integer));
Move (Ack.EventID,AckArray[10],sizeOf(Integer));
try
ClientPortIdContext.Connection.IOHandler.Write(AckArray);
except
end;
end;
请提供一个显示两端实际代码的列表。TCP是一个字节流,
IOHandler.Write()
在发送多个线程时不会以任何方式分隔数据,也不会防止并发问题。您有责任在自己的代码中处理所有这些,但听起来您并不是。如果看不到您的实际代码,很难说。这不是答案。你应该把这个贴出来,作为对你原来问题的编辑。好的,我明白了。我是个写作新手。对不起,我将来会做得更好。