TIdUDPServer到硬件设备的发送接收命令即时通信(张无忌大哥请进)(200分)

  • 主题发起人 主题发起人 Neo_leaf
  • 开始时间 开始时间
N

Neo_leaf

Unregistered / Unconfirmed
GUEST, unregistred user!
UDPServer : TIdUDPServer;
lbLog : TListBox;
启动服务:
procedure TFrm_UDPServer.btnStartClick(Sender: TObject);
begin
try
UDPServer.DefaultPort := StrToInt(EdtPort.Text);
UDPServer.Active := True;
lbLog.Items.Add('启动服务器端成功!');
except
lbLog.Items.Add('启动服务器端失败!');
end;
end;

procedure TFrm_UDPServer.BtnSendClick(Sender: TObject);
var
sBuf, sTest : AnsiString;
Buf: array [0..1023] of Char;
iSize,i: Integer;
begin
sBuf := Trim(EdtSendData.Text); //'40 40 40 40 01 fb 05 00 00 00 00 21 00 01 00 00 23';
sBuf := StringReplace(sBuf, ' ', '', [rfReplaceAll]);
iSize := Length(sBuf) div 2;
ZeroMemory(@Buf, SizeOf(Buf));
HexToBin(PChar(@sBuf[1]), Buf, SizeOf(Buf));
sTest := '';
for i := 0 to iSize-1 do
sTest := sTest + Buf;
UDPServer.SendBuffer(Trim(EdtDesIP.Text),StrToInt(EdtDesPort.Text),Buf, iSize);
(这里发送一条命令,是Connect Device的,如果连续发送多条命令,有验证密码、读取设备等)
{
UDPServer.SendBuffer(Trim(EdtDesIP.Text),StrToInt(EdtDesPort.Text),‘check psw’, iSize);
UDPServer.SendBuffer(Trim(EdtDesIP.Text),StrToInt(EdtDesPort.Text),‘Get Device Id’, iSize);
}
lbLog.Items.Add(s);
end;

读取返回值:
procedure TFrm_UDPServer.UDPServerUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
DataStringStream: TStringStream;
i : Integer;
b : byte;
begin
DataStringStream := TStringStream.Create('');
try
DataStringStream.CopyFrom(AData, AData.Size);
s := '';
DataStringStream.Position := 0;
while(DataStringStream.Position<DataStringStream.Size)do
begin
try
DataStringStream.Read(b,1);
s := s+IntToHex(b,2);
except
end;
end;
end;
end;
-----------------
现在是这样的,当发送一条命令时,在OnUDPRead事件里读取返回结果,没问题;
但是,当我同时发送三条命令时,则,程序的运行顺序是:
1、连续运行三条发送命令
2、进入OnUDPRead事件里读取返回结果(三个结果一起读出)。
我本来想,应该是发送一条命令后立即去读结果,然而不是这样的,
请问各位,
该如何做才可以使其发送一条命令后就立即去读结果??
200分呈上。。。。。。
 
张无忌让我来问题你


他说他不来了
 
大哥,别玩我了,
快急死了,
无论谁解决,分照给,
 
在读里设置一个标志,读到了,才允许发一条;
 
要不要用线程技术,
线程不熟,
不知道如何用,
 
To:QSmile,
知道你是高手,
不要吝啬您的知识了,
不知道和IdUDPServer.ThreadedEvent这个属性有没有关系,
但是我把它设置为True/False都没什么效果啊,
不知道怎么回事,
望大家指教。。。。
 
如果你必须一条命令,一条返回信息,真的可以考虑
来自:金卡绣球jk8.com, 时间:2006-7-12 18:55:06, ID:3503986
在读里设置一个标志,读到了,才允许发一条;
设置标志,发命令
reprat
循环等待结果回来
until 标识结果已经返回,退出循环
 
To:zywcd,金卡绣球jk8.com,

这样做的话,我怕死机,
你想,假如发了一条错的命令,这样的话,机器肯定没有返回值,
那么,程序就会进入死循环,
有没有其他办法了呢,
UDPServer.ThreadedEvent:= True;
这样做了后,还是不行,
 
问答式发送就可以解决了,您上面写的,如果发送的条数再多很多的话,估计会丢失.
 
按我上面的代码改造下,
应该如何呢,
 
楼主的是UDP粘包,把三次的包一次读完,你的数据量小,可能是IdUdpServer合并了。
1.要么用应答式的,发送同步命令,发送一条命令值到有返回结果在发第二条,这样你又
想&quot;===
假如发了一条错的命令,这样的话,机器肯定没有返回值,
那么,程序就会进入死循环,
有没有其他办法了呢,
&quot;===
告诉你这样可行的,不是有发送超时吗?为什么不处理超时,就算是你上面的那样,也要处
理超时呀。
 
为了避免死机,我通常在循环的时候加上时间判断,如果超过100ms,我认为是对方无应答,退出循环。你当然不能做成死等,那样对方不应答自然死机了。
 
reprat
循环等待结果回来
until 标识结果已经返回,退出循环
----------------
用这种方式,
并加“超时处理机制”,
但是还不行,
仍然是原来的错误,
不即时返回结果,
 
怎样可以手动触发TIdUDPServer. OnUDPRead事件,
 
可以采用waitfor方式去处理
 
结果很让我失望,
但还是揭贴了,
也不指望什么了,
几乎都是来混分的,
以后不来发帖了,浪费时间,求人不如求己!!!
 
一般来说不要针对什么控件来提问。
而是尽可能从原理上来提问,以找到问题的根源。

不然别人没用过这类控件,或没用到这方面,根本就无法回答。

你的问题是 UDP 通讯时的“粘包”问题。

一般我是这样处理的。先在 OnRead 里读出所有数据,从头开始。一个Byte 一个 Byte 的分析。
 
定一个全局缓冲

m_Buffer:array[0..8192] of byte; // 要够大
再定一个
m_BufPos:integer; // 这个表示 m_Buffer 中的有效数据个数。
在 OnRead 里
先 把新来的数据写到 m_Buffer 中。从 m_Buffer[m_BufPos] 开始向里写。
写完后 m_BufPos := m_BufPos + 写入的字节数。
然后再调用另一个函数来专门处理包

procedure PrecessPacket;
begin
1。 比较 m_BufPos 是否大于等于包长度? 小于包长度表示读到的数据不够,不做处理 exit
2. 从 m_Buffer[0] 开始找包头.找到包头,开始处理
3. 处理完一个包后, 把 m_Buffer 里的数据向先COPY.把处理过的数据,覆盖了。同时 m_BufPos := m_BufPos - 处理了的字节数。
2,3 循环。直到余下的字节数小于包长度。
end;


//明白了没?
 
明白了,多谢你,
为什么不早说呢?
当时是搞错了方向,
现在经过一个朋友的指点已搞定,
 
后退
顶部