4

我有一个用 libevent 编码的 TCP-Brodcast-Server,它执行以下操作:

Read data from a client
...
Transform the data
... 
//Write data to all connected clients   
for (int i = 0; i< connected clients; i++){
    // write Syscall for every client
    write(clientfd[i], "Transformed Data", lenofdata) 

}

现在我想提高性能并减少系统调用的数量。我不想以顺序方式将转换后的数据写入每个套接字并在每次写入套接字时进行系统调用,我想只使用一个系统调用将数据写入所有连接的客户端,如下所示:

Read data from a client
...
Transform the data
... 

// one single write Syscall for all connected clients
write(arrayWithManyClientFds, "Transformed Data", lenofdata) 

那可能吗?

编辑:最初我虽然发现了一个名为 lio_listio 的系统调用,这里将其描述为一个“重要的函数,因为这意味着您可以在单个系统调用的上下文中启动大量 I/O(意味着一个内核上下文切换)。 "

不幸的是 lio_listio() 接缝不适用于套接字,因为它在此处说明:“AIO 在套接字上读写 [不支持](不返回显式错误,但默认为同步或非 AIO 行为) "

所以我仍在寻找解决方案,如果有的话!

4

2 回答 2

4

不,这不对。但是,如果它让您感觉更好,系统调用只会将数据复制到内核缓冲区,然后操作系统会根据自己的时间将数据写入线路上,这是 IO 时间并且比 CPU 慢得多,所以这里的性能问题是最小,我怀疑它会成为你的瓶颈。另一种可能的解决方案是使用广播地址或多- 但这些解决方案存在问题,并且在大多数路由器和网络上都被阻止。

不支持此类功能的原因之一是 IP 数据包无法轻松发送给多个接收者 - 每个数据包都包含接收者 MAC 和 IP 地址,并且每个接收者可能正在侦听不同的 TCP 端口这也是数据包的一部分,因此每个接收者对数据包的处理都是不同的,因此在内核或用户程序中都需要对套接字进行循环 - 而且这不是内核必需或合理的功能来实施。

于 2013-10-19T13:02:40.290 回答
0

如果所有客户端都在同一个网络上,您可以使用带有 SO_BROADCAST 选项的 UDP 套接字。

这样,当一台计算机“发送”消息时,所有其他计算机都会“接收”该消息并根据需要进行更新。

此外,出于@immortal 指出的相同原因,如果消息必须通过路由器才能到达客户端,这将不起作用。

您可以创建一组基于 UDP 的代理来接收广播消息,然后每个代理将使用 TCP 将其转发给客户端。这样,至少减少了发送消息的进程的负载,并由网络上的其他计算机共享。

于 2013-10-26T01:11:48.953 回答