我正在尝试在管道和unix套接字之间选择IPC机制。
两者都支持 select()
和 epoll()
函数,这非常棒。
现在,管 Prop 有 4kB(截至今天)的“原子”写入,这是由 Linux 内核保证的。
unix 套接字是否存在这样的功能?我找不到任何文件明确说明这一点。
假设我使用 UNIX 套接字并从客户端写入 x 字节的数据。我确定当我的服务器的 select()
崩溃时,这些 x 字节将被写入套接字的服务器端吗?
对于同一主题,使用 SOCK_DGRAM 是否可以确保写入是原子的(如果可能的话),因为数据报应该是单个明确定义的消息?
那么使用 SOCK_STREAM 作为传输模式会有什么区别呢?
提前致谢。
最佳答案
管道
是的,非阻塞容量通常为 4KB,但为了获得最大的可移植性,您最好使用 PIPE_BUF
常量。另一种方法是使用非阻塞 I/O。
man 7 pipeline
中提供的信息比您想了解的更多。
Unix 数据报套接字
在数据报套接字上使用send
系列函数进行写入确实保证是原子的。对于 Linux,它们也很可靠,并且保留顺序。 (这使得最近引入的 SOCK_SEQPACKET
让我有点困惑)man 7 unix
中有很多关于此的信息。
最大数据报大小取决于套接字。它可以使用 SO_SNDBUF
上的 getsockopt/setsockopt
进行访问。在 Linux 系统上,它的范围介于 2048 和 wmem_max
之间,默认值为 wmem_default
。例如,在我的系统上,wmem_default = wmem_max = 112640
。 (您可以从 /proc/sys/net/core
中阅读它们)有关此内容的最相关文档位于 man 7 socket
中的 SO_SNDBUF
选项。我建议您自己阅读它,因为它描述的容量加倍行为一开始可能会有点令人困惑。
流和数据报之间的实际差异
流套接字仅在连接状态下工作。这主要意味着他们一次只能与一个同伴通信。作为流,它们不能保证保留“消息边界”。
数据报套接字已断开连接。他们(理论上)可以同时与多个对等方进行通信。它们保留消息边界。
[我认为新的 SOCK_SEQPACKET
介于:连接和边界保留之间。]
在 Linux 上,两者都是可靠的并且保留消息顺序。如果您使用它们来传输流数据,它们的性能往往相似。因此,只需使用与您的流程相匹配的那个,并让内核为您处理缓冲。
比较流、数据报和管道的粗略基准:
# unix stream 0:05.67
socat UNIX-LISTEN:u OPEN:/dev/null &
until [[ -S u ]]; do :;done
time socat OPEN:large-file UNIX-CONNECT:u
# unix datagram 0:05.12
socat UNIX-RECV:u OPEN:/dev/null &
until [[ -S u ]]; do :;done
time socat OPEN:large-file UNIX-SENDTO:u
# pipe 0:05.44
socat PIPE:p,rdonly=1 OPEN:/dev/null &
until [[ -p p ]]; do :;done
time socat OPEN:large-file PIPE:p
这里没有任何统计意义。我的瓶颈可能是读取大文件。
关于sockets - unix 套接字上的原子写入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4669710/