我有一个用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的系统调用,它被描述为here,因为它意味着你可以在单个系统调用的上下文中启动大量I / O(意味着一个内核上下文切换)。 )“。
不幸的是lio_listio()接口不适用于套接字,因为它已声明为here:“AIO在套接字上读写[不受支持](不会返回显式错误,但默认为默认为同步或者更确切地说是非AIO行为)“
所以我仍在寻找解决方案,如果有的话!
答案 0 :(得分:4)
不,不是。但是如果它让你感觉更好,那么系统调用只会将数据复制到内核缓冲区,然后操作系统会在自己的时间内写入数据,这个时间是IO时间并且比CPU慢得多,所以这里的性能问题是最小化,我怀疑它会成为你的瓶颈。 另一种可能的解决方案是使用broadcast address或Multicast - 但这些解决方案在大多数路由器和网络上都存在问题并被阻止。
不支持此类功能的原因之一是IP数据包无法轻松发送给多个收件人 - 每个数据包都包含接收者MAC和IP地址,每个收件人可能正在侦听不同的TCP端口也是数据包的一部分,因此每个接收者对数据包的处理是不同的,因此在内核或用户程序中需要在套接字上进行循环 - 并且它不是必需的或合理的功能供内核实现。
答案 1 :(得分:0)
如果所有客户端都在同一网络上,则可以使用带有SO_BROADCAST选项的UDP套接字。
这样,当一台计算机发出消息“发送”时,所有其他计算机都会“回复”。消息并根据需要进行更新。
此外,出于与@immortal所指出的相同的原因,如果消息必须通过路由器才能到达客户端,这将无效。
您可以创建一组接收广播消息的基于UDP的代理,然后每个代理将使用TCP将其转发到客户端。这样,至少发送消息的进程的负载就会减少并由网络上的其他计算机共享。