10

与我一起工作的开发团队的一部分人面临着编写服务器以与我们的产品集成的挑战。我们有一些提供 C SDK 的低级传感器设备,我们希望通过网络共享它们以供收集数据的人们使用。听起来很简单,对吧?有人会将传感器设备连接到建筑物一部分的机器并运行我们的服务器,从而与网络的其余部分共享设备。然后客户端将通过我们的应用程序连接到该服务器并从设备收集传感器读数。

我创建了一个简单的、与语言无关的网络协议和一个 Java 参考实现。问题在于创建一个可与仅提供用 C 编写的 SDK 的设备一起使用的实现。我们正在考虑执行以下操作:

  1. 创建轮询线程,收集和存储每个连接设备的最新读数。
  2. 使用多线程服务器将每个传入连接分离到工作线程。
  3. 当工作线程接收到传感器读取请求时,轮询线程收集的最新值将被发送回客户端。

这是很多线程,尤其是在 C 中。所以,回顾一下,一般要求是:

  • 在 Windows XP/Vista、Linux 和 OS X 机器上运行
  • 用 C 或 C++ 编写,与我们拥有的 C SDK 交互
  • 接受可变数量的同时连接(工作线程)
  • 必须使用线程,而不是分叉(不想处理另一层 IPC)

谁能建议一个库,最好是一些示例代码来开始使用?

4

11 回答 11

13

我使用Boost.ThreadBoost.Asio在 Windows 和 Linux 系统上构建了一个多线程服务器。这些教程使入门变得容易。

于 2008-12-20T14:57:53.130 回答
9

编写这样一个服务器的最好方法是不编写一个,重新架构你的系统,这样就没有必要了,和/或重用已经存在的组件。因为:

有人会将传感器设备连接到建筑物一部分的机器并运行我们的服务器,从而与网络的其余部分共享设备。

如果您的代码存在漏洞(当您从头开始用 C++ 编写并发明新协议时,它可能会存在漏洞),这也有可能与网络的其他部分共享整个机器。

所以,反过来做。在具有传感器硬件的机器上安装一个简单的客户端,然后始终或定期运行它,并将结果推送(发布)到中央服务器。中央服务器甚至可以是标准的网络服务器。或者它可能是一个数据库。(请注意,这两个都已经写好了 - 不需要重新发明轮子 ;-)

然后,您的应用程序将以您现在想到的相同方式工作,但是它从数据库而不是传感器收集数据。然而,在带有传感器的机器上运行的部分已经从一个多线程自定义服务器的噩梦缩小到一个漂亮的小单线程命令行客户端,它只进行传出连接,并且可以从 cron 运行(或在 windows 上等效) )。

即使您需要实时数据收集(根据您的描述,听起来您不需要),传感器收集器作为客户端而不是服务器仍然可能更好。让它打开与中央收集器(或其中一组)的长期连接,并等待提供其数据的指令。

编辑: ceretullis 和 pukku 的答案表明使用多播对此有一个很好的变化 - 请参阅此答案和评论

于 2008-12-20T16:04:28.597 回答
7

Douglas Schmidt 的 ACE(自适应通信环境)是一个成熟的、 高度可移植的开源框架,用于构建高性能多线程服务器。它主要针对电信应用,但已用于各种项目。它还带有一个名为TAO的对象请求代理(如果您喜欢CORBA

该框架的一个声名是它支持许多线程模型(线程池、每个请求的线程、异步+线程等),因此您可以以最适合您的应用程序的方式使用它的线程管理。这实际上是系统最有趣的特性——服务器框架功能开箱即用。我在这里看到的大多数其他库仍然需要您自己实现大部分功能。

有相当多的电子文档几本关于它的书籍。它不是最温暖和最蓬松的系统,并且真正为速度而不是舒适而构建 - 但我们使用的是 C++。您可能会发现,了解 ACE 比尝试重建功能和调试所有同步要少得多。

哦,顺便说一句,它是免费的,就像在演讲中一样 - 就像在啤酒中一样。如果您想要一条商业路线,还有一个顾问生态系统将为它提供支持和指导服务。可以在此处找到包含一些代码片段的教程。

于 2008-12-20T15:13:58.807 回答
4

我会使用QT。它具有跨平台线程支持。好的文档:

QT 线程文档

他们的信号/槽消息机制也在线程之间无缝工作。

于 2008-12-20T14:58:16.297 回答
4

不是你的问题的真正答案,但既然听起来你实际上比 C/C++ 更熟悉 Java,为什么不继续你的参考实现,并使用Java Native Interface连接到 SDK 。(我从未真正使用过它,但我认为它对这类情况非常有用。)

或者,您可以轻松编写一个使用 SDK 的简单 C 程序,然后将数据发送到您的 Java 程序,例如使用基于套接字的流。这样,您可以再次处理 Java 中更困难的事情。

于 2008-12-20T15:01:03.717 回答
3

我还想推荐The Spread Toolkit,它(根据项目的网站)是“一个开源工具包,它提供了一种高性能的消息传递服务,该服务对跨局域网和广域网的故障具有弹性”。在听起来与您的情况非常相似的情况下,我已经使用了几次。本质上,它为您提供了frankodwyer 建议的服务器。

Spread 守护程序(即服务器)不是多线程的,但它非常快,并且可以很好地扩展到至少成百上千的客户端。此外,该协议支持可靠的 IP 多播,这(在多客户端环境中)可以为您(在性能方面)提供明确的优势,以对抗仅使用点对点 TCP 或 UDP 连接实现的任何内容。(但是:不要尝试自己实现可靠的 IP 多播......显然,Spread 项目已经产生了许多博士/硕士论文作为副产品 - 或者它是作为副产品的工具包,而主要重点一直是学术研究?我真的不知道......)。

由于 Spread 具有 C 和 Java 客户端 API(加上 Python),因此听起来非常适合您的问题。他们有两种许可模式;第一种选择接近BSD。它当然是跨平台的(关于客户端和服务器)。

但是,Spread(当然)不会为您做所有事情。最突出的可能是,它不做持久性(即,如果您的客户端离线或无法接收消息,Spread 将不会缓冲它们,至少超出非常少量的消息)。但幸运的是,在 Spread 所保证的基础上推出您自己的持久性实现并不是很困难(好吧,我什至不知道这样的问题对您是否重要)。其次,Spread 将您的消息限制为每条 100 KB,但该限制也很容易绕过,只需让发送者将一条大消息分成许多较小的消息,然后在接收者处将它们连接起来。

于 2008-12-20T17:36:18.333 回答
2

我使用libevent来复用网络 I/O。您应该将其视为 Boost.Asio 的替代品。

当文件描述符上发生特定事件或达到超时后,libevent API 提供了一种执行回调函数的机制。目前,libevent 支持 /dev/poll、kqueue、事件端口、select、poll 和 epoll。

于 2009-08-23T06:54:36.040 回答
1

我同意 frankodwyer 的观点,将协议从拉模式转变为推模式。

每当共享服务运行时,让连接了传感器的计算机通过 UDP 多播以 100Hz(或为您的传感器制作的任何内容)广播读数。然后编写读取多播数据的客户端。

或者,您可以使用广播 UDP 而不是多播。

顺便说一句,这就是有多少 GPS、激光雷达和其他传感器在做事。

于 2008-12-20T17:17:20.990 回答
0

使用跨平台 API 或创建您自己的 API,您可以在每个架构上进行更改。

也修改这个:http ://www.goingware.com/tips/getting-started/

于 2008-12-20T14:52:29.163 回答
0

如果你想使用 C(而不是 C++),NSPR 库可能会提供你需要的东西......

于 2008-12-20T15:12:03.710 回答
-2

我强烈建议您考虑原型设计模式。

我使用这种模式在 C++ 中编写了一个与协议无关的服务器,从 HTTP Web 服务到自定义专有二进制协议,我都使用了该服务器。

基本上,这个想法是这样的:

服务器负责在特定端口上接受()传入连接并创建线程(或进程)来处理这些连接。

当您尝试构建通用服务器时,您会意识到如果不对协议做出假设,您将无法真正读取或写入任何数据......因此,诀窍是使用原型模式。

使用纯“HandleConnection() = 0”方法创建一个“ConnectionHandlerBase”类。使服务器类的用户使用他们自己的实现来继承这个类。此外,该类实现了一个“Clone()”方法,该方法返回自身的副本......这样服务器可以创建它的新实例而无需知道它的类型......然后当您获得连接时,调用“Clone ()” 在您的原型实例上,并让处理线程在此对象上调用“HandleConnection()”。

在应用程序启动时,服务器类的用户必须调用如下内容:

“Server.AttachConnectionPrototype(&MyConnectionObject);”

于 2008-12-20T15:19:31.557 回答