在C / C ++中实现跨平台,multithreading服务器的最佳方法是什么?

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

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

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

这是很multithreading,特别是在C中。因此,要审查,一般要求是:

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

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

我已经使用Boost.Thread和Boost.Asio在Windows和Linux系统上构建了一个multithreading服务器。 这些教程使您可以轻松入门。

编写此类服务器的最佳方法不是编写一个服务器,而是重新构建系统以使其不必要,和/或重用已经存在的组件。 因为:

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

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

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

然后,您的应用程序的工作方式与您现在的工作方式相同,但它会从数据库而不是传感器收集数据。 然而,在带有传感器的机器上运行的部件已经从multithreading自定义服务器噩梦缩小到一个很好的小型单线程命令行客户端,它只能进行传出连接,并且可以从cron运行(或者在Windows上运行)。

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

编辑:ceretullis和pukku的答案建议使用多播这是一个很好的变化 – 请参阅此答案和评论

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

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

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

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

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

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

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

QT线程文档

它们的信号/插槽消息传递机制也可以在线程之间无缝协作

我还想推荐The Spread Toolkit ,它(根据项目的网站)是“一个开源工具包,提供高性能的消息服务,可以抵御局域网和广域网的故障”。 在与你的声音非常相似的情况下,我曾多次使用过它。 从本质上讲,它为您提供了frankodwyer建议的服务器。

Spread守护程序(即服务器)不是multithreading的,但它确实很快并可以扩展到至少数百或数千个客户端。 此外,该协议适用于可靠的IP多播,(在多客户端环境中)可以为您(性能方面)提供明确的优势,防止仅使用点对点TCP或UDP连接实现的任何内容。 (但是:不要试图自己实现可靠的IP多播……显然,Spread项目已经产生了许多博士/硕士论文作为副产品 – 或者它是作为副产品的工具包,而主要强调总是学术研究?我真的不知道……)。

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

但是,Spread(当然)不会为您做任何事情。 也许最重要的是,它不会持久化(即,如果您的客户端处于脱机状态或无法接收消息,Spread将不会缓冲它们,至少超过极少数的msg)。 但幸运的是,在Spread确保的基础上推出自己的持久性实现并不是很困难(我甚至不知道这样的问题对你来说是否重要)。 其次,Spread将你的消息限制为每个100千字节,但是这个限制也很容易规避,只需让发送者将一个大消息切换成一些较小的消息,然后在接收器处连接它们。

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

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

我同意frankodwyer,将协议从拉模型转换为推模型。

当共享服务运行时,使用连接的传感器的计算机以100Hz(或传感器以后的任何产品)通过UDP多播广播读数。 然后编写读取多播数据的客户端。

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

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

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

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

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

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

我使用这种模式在C ++中编写一个与协议无关的服务器,我已经将其用于从HTTP Web服务到自定义专有二进制协议的所有内容。

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

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

当您尝试构建通用服务器时,您意识到在不对协议进行假设的情况下,您无法真正读取或写入任何数据……因此,诀窍是使用原型模式。

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

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

“Server.AttachConnectionPrototype(&MyConnectionObject);”