您需要首先决定要使用哪种套接字通信方式:
同步 - 意味着所有低级操作都是阻塞的,通常您需要一个线程用于接受,然后需要线程(读取线程或 io_service)来处理每个客户端。
异步 - 意味着所有低级操作都是非阻塞的,在这里你只需要一个线程(io_service),并且你需要能够在某些事情发生时处理回调(即接受、部分写入、读取结果等) .)
方法 1 的优点是它比 2 更容易编码(??),但是我发现 2 最灵活,事实上,使用 2,默认情况下您有一个单线程应用程序(内部事件回调是在一个独立的线程到主调度线程),当然2的缺点是你的处理延迟会影响下一个读/写操作...当然你可以使用方法2创建多线程应用程序,但反之则不然(即单线程 1) - 因此灵活性......
所以,从根本上来说,这一切都取决于风格的选择......
EDIT:更新了新信息,这很长,我懒得写代码,boost 文档中有很多内容,我将简单地描述一下正在发生的事情,以便您受益......
[主线]
- 声明 io_service 的实例
- 对于您要连接的每个服务器(我假设此信息在开始时可用),创建一个类(例如ServerConnection
),并在此类中,使用上面相同的 io_service 实例创建一个 tcp::socket,并在构造函数本身中调用async_connect
,注意:此调用是调度连接请求,而不是真正的连接操作(这要等到稍后才会发生)
- 一旦所有ServerConnection
对象(以及它们各自排队的 async_connects),调用run()
在 io_service 实例上。现在主线程被阻塞,无法在 io_service 队列中调度事件。
[asio线程] 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 将耗尽要分派的事件,并且 run() (您在主线程中调用)将结束。
现在,至于写作,这有点棘手。如果您的所有写入都是作为读取调用(即在 asio 线程中)处理数据的一部分完成的,那么您无需担心锁定(除非您的 io_service 有多个线程),否则在您的 write 方法中,将数据附加到缓冲区,并安排async_write_some
请求(使用 write_handler,当缓冲区被部分或完全写入时将被调用)。当 asio 处理此请求时,一旦数据写入,它将调用您的处理程序,并且您可以选择调用async_write_some
再次,如果缓冲区中还有更多数据,或者没有数据,则不必费心安排写入。此时,我将提到一种技术,考虑双缓冲 - 我将就此保留。如果您在 io_service 之外有一个完全不同的线程并且您想要写入,则必须调用io_service::post
方法并传入一个要执行的方法(在您的ServerConnection
类)以及数据,io_service 将在可能的情况下调用此方法,并且在该方法中,您可以缓冲数据并可选择调用async_write_some
如果当前正在写入未进行中.
现在有一件非常重要的事情你必须小心,你绝对不能安排 async_read_some
or async_write_some
如果有已经有一项正在进行中,也就是说,假设您打电话给async_read_some
在套接字上,在 asio 调用此事件之前,您不得安排另一个事件async_read_some
,否则你的缓冲区中将会有很多垃圾!
一个好的起点是您在 boost 文档中找到的 asio 聊天服务器/客户端,它显示了如何使用 async_xxx 方法。请记住这一点,所有 async_xxx 调用都会立即返回(在几十微秒内),因此没有blocking操作,这一切都是异步发生的。http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/example/chat/chat_client.cpp http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/example/chat/chat_client.cpp,就是我提到的例子。
现在,如果您发现这种机制的性能太慢并且您想要线程化,您所需要做的就是增加主 io_service 可用的线程数量,并在 ServerConnection 中的读/写方法中实现适当的锁定你就完成了。