一次将数据写入多个套接字(一个Syscall)

时间:2013-10-19 12:56:24

标签: c sockets system-calls

我有一个用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行为)“

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

2 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:0)

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

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

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

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