假设以太网上有一些非PC设备,并且基于给定的API,我可以使用UDP与它们通信。
我想使用线程池和线程安全队列进行UDP通信。每个工作线程都有自己的indy TIdUDPclient实例。通信就像将一个UDP数据报发送到设备然后等待答案。答案是UDP数据报在数据段中具有> 2个字节。
设备由 TDevice 类实例表示。
TDevice = class(TObject)
private
...
FStatus: byte;
...
public
...
function GetStatus(): integer; //API commandID = 68 (Getting device Status)
end;
thPool 用于创建/管理线程并将作业推送到队列:
TthPool = class(TObject)
private
FQueue: TThreadedQueue<TrUDPdirectJob*>;
FthWorkers: TList<TthWorker>;
public
constructor Create( AthCount, AQueueDepth: integer); //creating the pool here
function SendCommand( ArSendJob: TrSendJob );
end;
function SendCommand(ArSendJob TrSendJob): integer;
begin
...
FQueue.PushItem( ArSendJob );
end;
TDevice 的一个功能是获取它所代表的硬件的状态,并根据收到的答案设置它的 FStatus 的值:
function TDevice.GetStatus(): integer; //command byte: 68
const
PARAMSLENGTH = 4;
var
rSendJob: TrSendJob*
begin
rSendJob.IP := self.FIP;
rSendJob.port := self.Fport;
rSendJob.commandID := 68;
rSendJob.paramslength := PARAMLENGTH ; //need to send the length (API req)
SetLength( rSendJob.params, PARAMSLENGTH );
rSendJob.params[0] := $A; //just some parameters along the commandID
rSendJob.params[1] := $B;
rSendJob.params[2] := $C;
rSendJob.params[3] := $D;
...
thPool.SendCommand( rSendJob ); //pushing the job to the queue
end;
*TrSendJob = record //Job define
ip: string;
port: integer;
commandID: byte;
params: Tparams; //Array of byte
paramslength: byte;
end;
从工作线程发送UDP数据报:
procedure TthWorker.Execute;
var
sendBuffer: TIDbytes;
rBuffer: TIdBytes;
rSendJob: TrSendJob;
begin
inherited;
repeat
FQueue.PopItem(rSendJob); //Getting the job from the queue
//Building the sending buffer
sendBuffer[0] := rSendJob. ... ;
...
FIdUDPclient.SendBuffer( rSendJob.IP, rSendJob.port, sendBuffer );
if FIdUDPclient.receiveBuffer(rbuffer, RECTIMEOUT_GLOBAL) >= 1 then
begin
//
end;
until Terminated;
end;
总之, thPool SendCommand 正在将作业推入队列,工作线程从队列中拉出作业并发送UDP数据报,然后它回到 rbuffer 中的答案字节。但此时,如何将receivebuffer的内容发送回 TDevice 实例进行处理?这样做的正确(OOP)方式是什么?我需要在 TDevice 方法中进行处理。
这是一个合适的解决方案,如果我在 TrSendJob 定义一个加号方法指针字段,那么工作线程知道调用哪个方法来处理缓冲区并设置 FState 值of TDevice ?
TProcessReceiveBuffer = function(ArBuffer: TIdBytes): integer;
TrSendJob = record //Job define
ip: string;
port: integer;
commandID: byte;
params: Tparams; //Tparams array of byte
paramslength: byte;
*ProcessReceiveBuffer: TProcessReceiveBuffer; //pointer to a TDevice method thats processing the receivebuffer
end;
或者,整个概念都是错误的。
答案 0 :(得分:2)
但是在这一点上,如何将receivebuffer的内容发送回TDevice实例进行处理?
您可以在TrSendJob
中添加TthWorker
对象指针,然后TDevice
将知道将TEvent
传递给缓冲区。
或者,您可以将缓冲区和TrSendJob
放入TthWorker
,然后让TDevice.GetStatus()
填充缓冲区并发出事件信号,然后让.button span {
font-family: 'Georgia';
text-transform: uppercase;
font-size: 13px;
color: #FFFFFF;
position: absolute;
top: 20px;
left: 40px;
z-index: 2;
background: url('http://mile.x3.rs/mile/palma/img/button.gif') no-repeat;
padding: 14px 37px 30px 37px;
}
.button:hover span:hover{background: url('http://mile.x3.rs/mile/palma/img/button_active.gif') no-repeat;}
.button:hover span,
.button:hover:before {color: #88bfaa;}
等待事件信号并处理缓冲区。