在Java和C#中,我曾经能够通过让线程从阻塞流中读取传入的数据包,以及其他线程在同步函数中发送数据包来非常容易地编写双向套接字通信。
例如:
class MyBidirectionalSocket {
private OutputStream output;
public MyBidirectionalSocket(Socket socket) {
output = new BufferedOutputStream(socket.getOutputStream());
new ReadingThread(socket).start();
}
public synchronized void sendPacket(MyPacket packet) {
output.write(packet.getBytes());
output.flush();
}
private class ReadingThread extends Thread {
private InputStream input;
private ReadingThread(Socket socket) {
input = socket.getInputStream();
}
public void run() {
// real code would catch EOF exceptions, IO exceptions, etc...
while (true) {
MyPacket packet = readPacketFromStream(input);
doSomethingWithPacket(packet);
}
}
}
}
这对我来说总是很好用,因为我可以通过只读取传入流中的数据来实现readPacketFromStream,而不必担心数据何时到达 - 它只是阻塞直到数据可用或抛出EOFException(或IOException)如果流是关闭的,我可以在以后捕获。如果我想要高吞吐量,我甚至可以沿着各种工作线程分发传入的数据包。
现在我的问题是 - 我希望在C ++中使用跨平台实现做类似的事情。但是如何?
我一直在研究Boost库,因为它们似乎被广泛使用并且具有很多功能。它们主要提供两种与套接字通信的方式,一种是面向流的阻塞(使用套接字iostream),另一种是使用异步套接字通信(Boost asio)。
阻塞方法似乎只能工作半双工,因为iostream不是线程安全的(这个多线程应用程序可以并且将同时写入和读取!)。因此,据我所知,这是没有选择的。
在我的情况下,异步方法似乎是最好的选择。但是,我将收到数据块 - 可能包括数据包,半数据包或多个数据包,或其任何组合。 理想情况下,我会将收到的数据存储到流中,然后单独的线程可以执行阻塞读取。
因此我的问题是:
1)这样的多线程"管道"流存在于C ++中,无论是在标准库中,还是在Boost中,还是其他地方?我当然不是世界上第一个需要这样的东西的人,所以我怀疑它必须存在,尽管我不能找到它。
2)或者,是否有另一种模式 - 使用Boost或其他多平台库 - 可用于实现类似于上述代码的机制?
答案 0 :(得分:0)
boost :: asio非常灵活。您可以将它用于同步操作(阻止发送或接收数据)或异步操作(启动读/写操作,并在完成后在特定线程上获得回调)。您甚至可以使用两者的混合,例如异步读取和同步写入。
如果您想尽可能地遵循Java模型,您可以简单地坚持asio提供的同步操作。
这意味着如果您有一个类似
的套接字shared_ptr<boost::asio::ip::tcp::socket> socket;
启动一个额外的线程并使用来自socket->read(...)
的阻塞读取,并可能使用socket->write(...)
从另一个线程写入套接字。只要你不做2个并发读取这样的事情,这绝对是安全的。对于并发写入,您可能需要额外的互斥锁。
请注意,此同步写入/读取只是本机操作系统套接字API的一个非常小的包装器,它允许相同的。 asios power主要以异步变体的形式出现(但是它们看起来与Java代码不同,因此可能不太理想)。所以你甚至可以使用原生套接字。
关于asio中的更高级别包装器,ip::tcp::iostream stream
:
遗憾的是,我也不知道这是否是线程安全的,以及是否可以在同步套接字可以使用相同的双向配置。但我会期待它,因为否则它对大多数应用程序来说都是毫无价值的。