【发布时间】:2014-12-13 08:39:28
【问题描述】:
众所周知,回显服务器是从套接字读取数据并将该数据写入另一个套接字的服务器。
由于 Windows I/O 完成端口为您提供了不同的方式来做事,我想知道实现回显服务器的最佳方式(最有效)是什么。我一定会找到测试我将在此处描述的方式的人,并且可以为他/她做出贡献。
我的类是Stream,它抽象了一个套接字、命名管道或其他东西,以及IoRequest,它抽象了一个OVERLAPPED 结构和内存缓冲区来执行I/O(当然,既适合阅读和写作)。这样,当我分配IoRequest 时,我只是一次性为数据+OVERLAPPED 结构的内存缓冲区分配内存,所以我只调用一次malloc()。
除此之外,我还在IoRequest对象中实现了一些花哨和有用的东西,比如原子引用计数器等等。
说了这么多,我们来探索一下如何做最好的回显服务器:
-------------------------------------------- 方法 A。 ----------------------------------------------
1) “reader”套接字完成读取,IOCP 回调返回,你有一个IoRequest 刚刚完成了内存缓冲区。
2) 让我们将刚刚通过“读取器”IoRequest 接收到的缓冲区复制到“写入器”IoRequest。 (这将涉及memcpy() 或其他)。
3) 让我们在“阅读器”中使用ReadFile() 再次触发新的阅读,使用相同的IoRequest 阅读。
4) 让我们在“writer”中使用WriteFile() 启动一个新的写作。
-------------------------------------------- 方法 B。 ----------------------------------------------
1) “reader”socket 完成读取,IOCP 回调返回,你有一个 IoRequest 刚刚完成了内存缓冲区。
2) 不复制数据,而是将 IoRequest 传递给“写入者”进行写入,不使用 memcpy() 复制数据。
3) “读者”现在需要一个新的IoRequest 来继续阅读,分配一个新的或传递一个之前已经分配的,也许在新的写入发生之前刚刚完成写入。
因此,在第一种情况下,每个Stream 对象都有自己的IoRequest,使用memcpy() 或类似函数复制数据,一切正常。
在第二种情况下,两个Stream 对象确实相互传递IoRequest 对象,而不复制数据,但它有点复杂,您必须管理IoRequest 对象在两个Stream 之间的“交换”对象,可能会有同步问题的缺点(那些完成确实发生在不同的线程中呢?)
我的问题是:
Q1) 避免复制数据真的值得吗!?
使用memcpy() 或类似名称复制 2 个缓冲区非常 快,这也是因为 CPU 缓存被用于此目的。
让我们考虑一下,使用第一种方法,我可以从“读取器”套接字回显到多个“写入器”套接字,但是使用第二种方法我不能这样做,因为我应该创建 N 个新的 IoRequest 对象每个 N 个作者,因为每个 WriteFile() 都需要自己的 OVERLAPPED 结构。
Q2) 我猜当我使用WriteFile() 为 N 个不同的套接字触发新的 N 个写入时,我必须提供 N 个不同的 OVERLAPPED 结构 AND N 个不同的缓冲区来读取数据.
或者,我可以使用 N 个不同的 OVERLAPPED 触发 N 个 WriteFile() 调用,从 N 个套接字的 相同 缓冲区中获取数据?
【问题讨论】:
-
只需要回显数据吗?考虑使用 .NET。 .NET memcpy 与 C++ 一样快。很可能,大多数 CPU 不会用于具有此工作负载的托管代码。 .NET 解决了您的许多顾虑。
-
谢谢你,usr。回显数据不仅仅是我需要的。我只是以一般的方式想知道。我使用的是 C++,所以我不能使用 .NET 和托管的东西。我只是想知道我是否可以为此避免使用 memcpy(),因为 IOCP 可能允许您这样做。
标签: c++ windows sockets io iocp