使用boost套接字,我只需要一个io_service吗?

gri*_*ich 9 c++ sockets boost boost-asio

在几个不同的线程中有几个连接..我基本上做了一个使用boost/asio.hpp和tcp东西的基类..现在我正在读这个:http://www.boost.org/doc/libs /1_44_0/doc/html/boost_asio/tutorial/tutdaytime1.html 它说"所有使用asio的程序都需要至少有一个io_service对象." 所以我的基类应该有一个静态的io_service(这意味着所有程序只有1个,所有不同的线程和连接将使用相同的io_service对象)或者使每个连接都有自己的io_service?

谢谢你!

更新:好的,所以基本上我想要做的是一个基本客户端的类,它将有一个套接字.对于每个套接字,我将拥有一个始终接收的线程和一个有时发送数据包的不同线程.在这里查看之后:www.boost.org/doc/libs/1_44_0/doc/html/boost_asio/reference/ip__tcp/socket.html(因为我刚刚在这里做了超链接所以..所以每篇帖子只有1个)我能看到套接字类不是完全线程安全的..

所以有两个问题:1.基于我刚刚编写的设计,我是否需要为所有套接字提供1个io_service(意思是使其成为静态类成员)或者我应该为每个套接字分配一个?2.如何使其成为线程安全的?我应该把它放在一个"线程安全的环境"中,这意味着制作一个新的套接字类,它具有互斥量和不允许你同时发送和接收的东西,或者你有其他建议吗?也许我应该继续进行异步设计?(ofc每个套接字将有一个不同的线程,但发送和接收将在同一个线程?)

只是为了澄清:我正在做一个连接到很多服务器的tcp客户端.

Nim*_*Nim 11

您需要首先确定要使用的套接字通信方式:

  1. 同步 - 意味着所有低级操作都是阻塞的,通常需要一个接受线程,然后线程(读线程或io_service)来处理每个客户端.

  2. 异步 - 意味着所有低级操作都是非阻塞的,在这里你只需要一个线程(io_service),并且你需要能够在某些事情发生时处理回调(即接受,部分写入,读取结果等) .)

方法1的优点是代码(??)比2更简单,但我发现2是最灵活的,实际上有2,默认情况下你有一个单线程应用程序(在内部事件回调是在一个单独的线程到主调度线程),2的缺点当然是你的处理延迟命中下一个读/写操作...当然你可以使用方法2制作多线程应用程序,但反之亦然(即单螺纹1) - 因此灵活性......

所以,从根本上说,这一切都取决于风格的选择......

编辑:更新了新的信息,这是相当长的,我不能打扰编写代码,在提升文档中有很多,我只是简单地描述一下为你的利益发生了什么......

[主线程] -声明io_service对象的实例-每个要连接到服务器的(我假设该信息可在开始时),创建一个类(比方说ServerConnection),并在这个类中,创建一个TCP: :socket使用与上面相同的io_service实例,并在构造函数本身中调用async_connect,注意:这个调用是一个调度请求连接而不是真正的连接操作(这不会发生到以后) - 一旦所有ServerConnection对象(和他们各自的async_connects排队),调用run()io_service的实例.现在主线程被阻止调度io_service队列中的事件.

[asio thread] io_service默认情况下有一个调用调度事件的线程,你不控制这个线程,并且实现一个"多线程"程序,你可以增加io_service使用的线程数,但是一刻坚持下去,它会让你的生活变得简单......

asio将根据计划列表中准备好的事件调用ServerConnection类中的方法.排队的第一个事件(在调用run()之前)是async_connect,现在asio会在建立到服务器的连接时回调你,通常,你将实现一个handle_connect将被调用的方法(你将方法传递给async_connect调用).在handle_connect,您需要做的就是安排下一个请求 - 在这种情况下,您想要读取一些数据(可能来自此套接字),因此您可以调用async_read_some并传入一个函数,以便在有数据时收到通知.完成后,主asio调度线程将继续调度其他已准备好的事件(这可能是其他连接请求,甚至async_read_some是您添加的请求).

假设您被调用,因为其中一个服务器套接字上有一些数据,这是通过您的处理程序传递给您的async_read_some- 您可以随后处理此数据,按需要执行,但这是最重要的一点 - 一次完成后,安排下一个async_read_some,这样asio将提供更多的数据.非常重要的注意:如果你不再安排任何请求(即从处理程序退出无需排队),那么io_service执行完事件的调度和运行()(你在主线程中调用)将结束.

现在,至于写作,这有点棘手.如果所有的写入都是作为读取调用中数据处理的一部分完成的(即在asio线程中),那么您不必担心锁定(除非您的io_service有多个线程),否则在您的write方法中,将数据附加到缓冲区,如果缓冲区中剩余更多数据,则再次安排数据,如果没有,则不必费心安排写入.在这一点上,我将提到一种技术,考虑双缓冲 - 我会留下它.如果你有一个完全不同的线程在io_service之外并且你想写,你必须调用方法并传入一个方法来执行(在你的async_write_some请求(使用write_handler,当写入缓冲区时,将部分或完全写入).当asio处理此请求时,它将在写入数据后调用您的处理程序,并且您可以选择调用async_write_someio_service::postServerConnection然后,io_service将与数据一起调用此方法,然后在该方法中,您可以缓冲数据,并可选择async_write_some在写入当前未进行时调用.

现在有一个非常重要的事情,你必须要小心,你必须永远不要安排 async_read_someasync_write_some如果已经有一个正在进行,即让我们说你async_read_some在套接字上调用,直到asio调用此事件,你不能安排另一个async_read_some,否则你的缓冲区里会有很多废话!

一个很好的起点是您在boost文档中找到的asio聊天服务器/客户端,它显示了如何使用async_xxx方法.并记住这一点,所有async_xxx调用立即返回(在几十微秒内),因此没有阻塞操作,它都是异步发生的.http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/example/chat/chat_client.cpp,就是我所指的例子.

现在,如果您发现此机制的性能太慢并且您想要进行线程化,那么您需要做的就是增加主io_service可用的线程数,并在ServerConnection中的读/写方法中实现适当的锁定你完成了


Sam*_*ler 5

对于异步操作,您应该io_service为整个程序使用单个对象.无论是类的静态成员,还是在其他地方实例化都取决于您.多个线程可以调用它的run方法,这在Inverse的回答中有所描述.

多个线程可以调用io_service :: run()来设置一个线程池,从中可以调用完成处理程序.此方法也可以与io_service :: post()一起使用,以使用一种方法在线程池中执行任何计算任务.

请注意,已加入io_service池的所有线程都被视为等效,并且io_service可以以任意方式在它们之间分配工作.

如果您的处理程序不是线程安全的,请阅读有关链的信息.

strand被定义为事件处理程序的严格顺序调用(即没有并发调用).使用strands允许在多线程程序中执行代码,而无需显式锁定(例如使用互斥锁).


Inv*_*rse 1

io_service 为您的连接调用所有处理程序函数。因此,您应该运行一个线程,以便跨线程分配工作。这是解释 io_service 和线程的页面:

线程和 Boost.Asio