【问题标题】:Application that connects to multiple devices in Network连接到网络中的多个设备的应用程序
【发布时间】:2014-10-14 19:19:28
【问题描述】:

我的本​​地网络上有 X 个电子设备(气象站)变量,每个设备都提供到特定 IP 和端口的 ServerSocket 连接,我有一个连接到所有此类设备的应用程序,我的应用程序知道这些 IP和这些设备的端口,因为它们在数据库中注册,打开我的应用程序,我创建了一个动态的 [TClientSocket (Array)] 连接到这些设备中的每一个,这随后改变了很多信息,比如对话,询问温度所有设备,他们都会回答我,或者我可以通过内部操作询问一个温度、另一个湿度、另一个风速等。 今天我做了一个 FOR 循环,所有连接的设备都知道我的软件对设备进行了哪些操作,然后与每个设备进行随机对话,但这很慢,因为它增加了设备数量,从而使 FOR 变慢。我所做的是删除 FOR 的线程,我想知道这是否可能。 onConnect、OnRead 等......我的 TClientScojet 事件是在创建 TClientSocket 数组时分配的,所以我最终得到了这个期望的一个,然后使用另一个,不能同时满足所有设备。 我希望我可以将这个线程用于所有设备并同时满足,但不要主导概念和使用,如果有人知道我可以如何改进这段代码,我非常感激。

今天我用这个类我创建了扩展的TClientSocket:

type
  TTermoCenter = class(TClientSocket)
  private
    countSema: Thandle;
    access: TCriticalSection;
    ...
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Push(inObject: TPalavra; priority: Integer); virtual;
    function Pop(pResObject: pObject; timeout: Integer): Boolean;
  end;

这里是构造函数:

constructor TTermoCenter.Create(AOwner: TComponent);
var
  I: Integer;
begin
  inherited;
  access := TCriticalSection.Create;
  ...
end;

这是析构函数:

destructor TTermoCenter.Destroy;
var
  I: Integer;
begin
  ...
  access.Free;
  closeHandle(countSema);
  inherited;
end;

变量声明:

var
  termocenters: array of TTermoCenter;

创建表单时,我定义了数组的大小

SetLength(termocenters, dm.sqlTermocenter.RecordCount);

我根据数据库中的内容创建连接:

var
  SocketTmp: TTermoCenter;

  while not cds.Eof do
  begin
    SocketTmp := TTermoCenter.Create(nil);
    SocketTmp.name := 'cdsNome';
    SocketTmp.Port := 'cdsPorta';
    SocketTmp.ClientType := ctNonBlocking;
    SocketTmp.Host := 'cdsIP';
    // atribui eventos
    SocketTmp.OnRead := TCPRead;
    SocketTmp.OnConnect := TCPConnect;
    SocketTmp.OnDisconnect := TCPDisconnect;
    SocketTmp.OnError := TCPError;

    //Coloca no Array
    termocenters[I] := SocketTmp;
    try
      termocenters[I].Active := True;
      sleep(1000);
    except
      on E: Exception do
        frmMain.mmErros.Lines.Add(TimeToStr(now) + ' - ' + E.ClassName + ' CriaConexao : ' + E.Message);
        end;
      end;
    end;
  cds.Next;
end;
end;

这是我今天所拥有的代码的一个很好的总结,我想要一些帮助来实现线程。谢谢。

【问题讨论】:

  • 将字符串分配给TClientSocket.Port 不会编译。你确定你的代码可以编译吗?也不清楚为什么TCriticalSection 实例和Sleep 调用在这里。

标签: multithreading sockets delphi


【解决方案1】:

使用TClientSocket 事件可以正常工作,前提是您在具有消息循环的线程的上下文中创建TClientSocket 对象,例如主 UI 线程。

您正在使用非阻塞模式,因此设置Active=True 不会阻塞您的循环。连接将在后台发生。当您收到OnConnect 事件时,它会告诉您已连接的特定TCustomWinSocket,因此您知道可以开始向哪个特定设备发送命令。如果您收到OnError 事件,它会告诉您是否是连接错误,因此您可以知道哪些设备无法连接。

当OnRead 被触发时,它会告诉您正在发送数据的具体TCustomWinSocket,因此您知道哪个设备正在报告信息。由于您使用的是非阻塞模式,OnRead 事件提供的数据可能(并且通常会)不完整,因此只需将其缓冲到某处(例如使用TCustomWinSocket.Data 属性保存指向您将新数据附加到的缓冲区),并且仅从缓冲区中提取已完成的消息,将不完整的消息留在缓冲区中以供稍后完成。对于每条完整的消息,您可以根据需要使用/更新该特定设备的信息。

如果您在使用事件时遇到问题,请出示您的实际代码。到目前为止,您所展示的内容不足以诊断您遇到的任何问题。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
  • 1970-01-01
  • 2018-11-30
  • 2016-09-26
相关资源
最近更新 更多