网络客户端模拟器设计
我正在尝试用 C++ 设计一个软件,它将使用 **UDP 协议** 发送请求字节(遵循标准 **应用程序级** 协议,其要填充的字段将从文本文件中获取)。
现在这个客户端必须能够以非常高的速率发送这些请求..高达**每秒 2000 个事务**,并且如果在指定的超时内得到响应,也应该接收响应,否则不会接收到它
我将使用 boost 库来处理所有套接字,但我不确定它针对如此高速应用程序的设计:(
我想我必须使用高度多线程的应用程序(再次使用Boost)。我说得对吗?我是否必须为每个请求创建一个单独的线程?但我认为只有一个线程必须等待接收响应,否则如果有许多线程正在等待响应,我们如何区分我们已收到响应的线程请求!
希望这个问题是清楚的。我只是需要一些关于设计点和我可能遇到的疑似问题的帮助。
I am trying to design a software in c++ that will send request bytes (following a standard **application level** protocol whose fields to be populated will be taken from a text file) using **UDP protocol**.
Now this client must be able to send these requests at very high rate..upto **2000 transactions per second** and should also receive the response if it gets within a specified timeout else don't receive it
I will be using boost library for all the socket things but I am not sure about the design of it for such high speed application :(
I think I have to use a highly multi-threaded application (again Boost will be used). Am I right ? Do I have to create a seperate thread for each request ? But I think only one thread must be waiting to recieve the response else if many threads are waiting for a response how can we distinguish for which threads request we have got the response for !!
Hope that question is clear. I just need some help regarding the design points and suspected problems that I may face.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我现在正在开发自己的网络客户端,所以也许我可以提供一些建议和一些资源供参考。在这个领域有很多更有经验的人,希望他们能参与进来:)
首先,你的目的是提升。一旦您习惯了它们的组合方式,
boost ::asio
是一个用于编写网络代码的出色工具包。本质上,您创建一个io_service
并调用run
执行直到所有工作完成,或者调用runOne
执行单个 IO 操作。就其本身而言,这并没有多大帮助。其威力来自于您在自己的循环中运行runOne
,或在一个(或多个)线程上运行
run
函数:但是,值得注意的是 <一旦没有工作要做,code>run就会返回(这样你就可以告别该线程)。正如我在 Stackoverflow 上发现的,诀窍是确保它始终有事可做。解决方案在
boost::asio::io_service::work
中:上面的行确保您的线程在没有任何情况发生时不会停止。我认为这是一种保持活动的方法:)
在某些时候,您会想要创建一个套接字并将其连接到某个地方。我创建了一个通用的 Socket 类(并从中派生了一个文本套接字以创建缓冲输入)。我还想要一个基于事件的系统,其工作方式与 C# 非常相似。我在下面为您概述了这些内容:
第一步,我们需要一种传递参数的通用方法,因此,
EventArgs
:eventArgs.h
现在,我们需要一个人们可以订阅/取消订阅的事件类:
event.h
然后,是时候创建一个套接字类了。下面是头文件:
socket.h
(一些注释:
ByteVector
是typedef std::vector
)现在是实现。您会注意到它调用另一个类来执行 DNS 解析。我稍后会展示这一点。另外,我还省略了一些
EventArg
派生项。当套接字事件发生时,它们只是作为 EventArg 参数传递。socket.cpp
正如我所说的 DNS 解析,
Root::instance().resolveHost(_host, _port, anonResolve);
行调用它来执行异步 DNS: ,我需要一个基于文本的套接字,每次收到我的行(然后进行处理)时都会引发一个事件。这次我将省略头文件,只显示实现文件。不用说,它声明了一个名为
onLine
的Event
,每次完整接收到一行时都会触发该事件:关于上面的类需要注意的一些事情......它使用 < code>boost::asio::post 发送行。这允许它全部发生在 ASIO 以线程安全的方式管理的线程上,并允许我们对要发送的行进行排队。这使得它非常具有可扩展性。
我确信还有更多问题,也许我的代码没有帮助。我花了几天时间将它们拼凑起来并理解它,但我怀疑它实际上有什么用处。希望一些更好的人会浏览它并说“天哪,这
I'm halfway through a network client of my own at the moment, so perhaps I can impart some advice and some resources to look at. There are many more experienced in this area, and hopefully they'll chime in :)
Firstly, you're about boost. Once you get used to how it all hangs together,
boost::asio
is a great toolkit for writing network-code. Essentially, you create anio_service
and callrun
to execute until all work is complete, orrunOne
to perform a single IO action. On their own, this isn't that helpful. The power comes from when you either runrunOne
in it's own loop:, or run the
run
function on one (or more) threads:However, it is worth noting that
run
returns as soon as there is no work to do (so you can say goodbye to that thread). As I found out here on Stackoverflow, the trick is to ensure it always has something to do. The solution is inboost::asio::io_service::work
:The above line ensures your thread won't stop when nothing is going on. I view is as a means to keep-alive :)
At some point, you're going to want to create a socket and connect it somewhere. I created a generic Socket class (and derived a text-socket from that to create buffered input). I also wanted an event-based system that worked very much like C#. I've outlined this stuff for you, below:
First step, we need a generic way of passing arguments around, hence,
EventArgs
:eventArgs.h
Now, we need an event class which people can subscribe/unsubscribe to:
event.h
Then, it was time to create a socket class. Below is the header:
socket.h
(Some notes:
ByteVector
istypedef std::vector<unsigned char>
)And, now the implementation. You'll notice it calls another class to perform DNS resolution. I will show that afterwards. Also there are some
EventArg
-derivatives I have ommitted. They are simply passed as EventArg parameters when socket events occur.socket.cpp
As I said about DNS resolution, the line
Root::instance().resolveHost(_host, _port, anonResolve);
calls this to perform asynchronous DNS:Finally, I need a text-based socket that raised an event every time I line was received (which is then processed). I'll omit the header file this time and just show the implementation file. Needless to say it declares an
Event
calledonLine
which it fires every time a line is received in it's entirety:Some things to note about the class above... it uses
boost::asio::post
to send lines. This allows it to all occur on the threads that ASIO manages in a thread-safe way, and allows us to queue up lines to be sent as and when. This makes it very scalable.I am sure there are many more questions and maybe my code isn't helpful. I spent several days piecing it all together and making sense of it, and I doubt it's actually any good. hopefully some better minds will glance over it and go "HOLY CRAP, THIS
我不确定您是否需要“重度”多线程。大多数高速应用程序使用操作系统的轮询机制,其扩展性通常比线程更好。
该架构在很大程度上取决于您的应用程序需要的反应程度,即哪些组件负责生成输入和输出以及进行实际处理。
使用 boost::asio 解决问题的一种方法是拥有一个运行 boost::asio::io_service::run 方法的通信线程。 io_service 监听各种 UDP 套接字,并在消息到达时对其进行处理,可能会将它们发送到队列中,以便应用程序可以在主线程中处理它们。从主线程,您可以将消息发布到 io_services,以便主系统发送它们。
这应该可以让您毫无困难地达到每秒 2000 条消息。
另一种方法是通过从多个线程多次调用 boost::asio::io_service::run 方法来启动多个通信线程,从而允许其通信线程并行处理消息。
不过,对 Asio 的一点建议是:由于其异步架构,如果您遵循其逻辑并按照其预期的方式使用它,它会工作得更好。如果您发现自己使用了大量的锁并管理了许多线程,那么您可能做错了。仔细查看各种方法的线程安全保证,并研究提供的示例。
I'm not sure you need to go "heavy" multi-thread. Most high speed applications use the polling mechanisms of the operating system, which generally scale better than threads.
The architecture will depend a lot on how reactive your application needs to be, in terms of what components are responsible for generating inputs and outputs, and doing the actual processing.
A way to approach your problem using boost::asio would be to have a communication thread that runs the boost::asio::io_service::run method. The io_service listens on the various UDP sockets, and processes messages as they arrive, possibly sending them down a queue so that the application can process them in the main thread. From the main thread, you can post messages to the io_services for them to be sent by the main system.
This should allow you to climb up to 2000 messages per seconds without much difficulties.
An alternative would be to start several communication threads by calling the boost::asio::io_service::run method several times from several threads, allowing for messages to be processed in parallel by their communication thread.
One word of advice with Asio, though: because of its asynchronous architecture, it works better if you go within its logic and use it the way it is meant to. If you find out that you are using a lot of locks and managing many threads yourself, then you are probably doing it wrong. Look closely at the thread safety guarantees of the various methods, and study the provided examples.