本文参考communicate with unix sockets做了一些简单的测试,了解unix socket是如何通信的。
unix socket是常见的一种本地进程通信的方式(IPC), 其他的还有 shared memory, eventfd。
创建一个 STREAM socket
创建一个unix socket,作为server端,命令不会返回,会一直等待:
# nc -U /tmp/demo.sock -l
## nc, which is short for netcat.
##-l listen
## -U, --unixsock Use Unix domain sockets only
## --vsock Use vsock sockets only
查看这个socket的类型是STREAM,以及它的状态是listen。关于tcp和udp的socket的区别,不同于网络里面的tcp和udp,参考difference-between-unix-domain-stream-and-datagram-sockets以及communicate-with-unix-sockets。 还有FD,文件描述符,当linux进程要做I/O操作时,它需要通过读写文件描述符来完成操作。常见的例子有stdin, stdout, and stderr,它们分别map到文件描述符为 0, 1, 和 2.
# lsof /tmp/demo.sock
##the lsof command is a utility used to list and give information about files that are in use by processes.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nc 644501 root 3u unix 0xffff9b20795e2200 0t0 6951183 /tmp/demo.sock type=STREAM (LISTEN)
Network Sockets using SOCK_STREAM will use TCP, while those using SOCK_DGRAM will use UDP. Since UDP is unreliable by definition, any process that requires reliable data transfer over a network socket should use a network socket of type SOCK_STREAM. However, when it comes to Unix Sockets, both types are reliable. The difference between the two types for Unix Sockets is that the SOCK_DGRAM type preserves message boundaries but is connectionless. In contrast, the SOCK_STREAM type does not preserve message boundaries but is connection-oriented.
第二个终端用nc作为客户端,与这个socket通信:
# nc -U /tmp/demo.sock
test
这两个终端就会像管道一样,一端写回车以后,另一端会同步显示,两边的内容总是一样的,都可以写,都可以收到。此时,第三个终端查看现在的状态已经是connected:
# lsof /tmp/demo.sock
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nc 644501 root 4u unix 0xffff9b20791eee80 0t0 6951184 /tmp/demo.sock type=STREAM (CONNECTED)
创建一个udp的socket:
# nc -U /tmp/demo.socku -u -l
## -u代表udp
第二个终端查看,是DGRAM类型的,状态是unconnected:
# lsof /tmp/demo.socku
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nc 36400 root 3u unix 0xffff9441bcb54c80 0t0 3613087 /tmp/demo.socku type=DGRAM (UNCONNECTED)
第二个终端,使用这个socket开始传输一些数据,跟tcp的一样。
第三个终端,查看socket状态是connected
# lsof /tmp/demo.socku
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nc 644563 root 3u unix 0xffff9b2068958cc0 0t0 6951191 /tmp/demo.socku type=DGRAM (CONNECTED)
当server 端kill以后,继续输入内容,tcp:
# nc -U /tmp/demo.sock
test
you
sdfsdfsdf
sdfsdf
Ncat: Broken pipe.
当server端kill以后,继续输入内容,udp:
# nc -u /tmp/demo.socku -U
ste
sdf
Ncat: Connection refused.
和internet socket 比较:
- unix socket以文件名命令,而internet socket 是用ip和端口号;
- unix socket本机内进程之间通信,internet socket既可以本机通信也可以跨主机;
- 本机通信的话,用unix socket 效率更高,不用走TCP/IP协议栈,而且总是可靠传输;
- 底层的 API 非常相似;
启动一个虚拟机,并查看由qemu-kvm进程启动的unix socket有哪些:
# lsof -U | grep qemu-kvm
qemu-kvm 651492 qemu 12u unix 0xffff9b18fb4f2ec0 0t0 7275481 type=STREAM (CONNECTED)
qemu-kvm 651492 qemu 22u unix 0xffff9b18d3031540 0t0 7297553 /var/lib/libvirt/qemu/channel/target/domain-1-rhel/org.qemu.guest_agent.0 type=STREAM (LISTEN)
qemu-kvm 651492 qemu 23u unix 0xffff9b18d3036e80 0t0 7297554 /var/lib/libvirt/qemu/domain-1-rhel/monitor.sock type=STREAM (LISTEN)
qemu-kvm 651492 qemu 27u unix 0xffff9b18fb4f5500 0t0 7432217 type=STREAM (CONNECTED)
qemu-kvm 651492 qemu 31u unix 0xffff9b18d3036600 0t0 7339139 /var/lib/libvirt/qemu/domain-1-rhel/monitor.sock type=STREAM (CONNECTED)
qemu-kvm 651492 qemu 110u unix 0xffff9b207acfaec0 0t0 7080806 /var/lib/libvirt/qemu/channel/target/domain-1-rhel/org.qemu.guest_agent.0 type=STREAM (CONNECTED)
这里出现了guest agent以及qemu mointor.sock, 但是为什么出现多次?qemu命令行如下:
-chardev socket,id=charmonitor,fd=23,server=on,wait=off \
-mon chardev=charmonitor,id=monitor,mode=control
-chardev socket,id=charchannel0,fd=22,server=on,wait=off \
-device '{"driver":"virtserialport","bus":"virtio-serial0.0","nr":1,"chardev":"charchannel0","id":"channel0","name":"org.qemu.guest_agent.0"}' \
-chardev socket,id=chrtpm,path=/run/libvirt/qemu/swtpm/1-rhel-swtpm.sock \
-tpmdev emulator,id=tpm-tpm0,chardev=chrtpm \
其中最后的tpm相关的socket是tss进程关联的,为什么也是有两个?是为了有多个连接吗?
# lsof /run/libvirt/qemu/swtpm/1-rhel-swtpm.sock
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
swtpm 651475 tss 4u unix 0xffff9b18cd499dc0 0t0 6999418 /run/libvirt/qemu/swtpm/1-rhel-swtpm.sock type=STREAM (LISTEN)
swtpm 651475 tss 8u unix 0xffff9b18fb4f0440 0t0 6999420 /run/libvirt/qemu/swtpm/1-rhel-swtpm.sock type=STREAM (CONNECTED)