浅谈 socket
最近在写 MIT 6.824 的 lab,其中读作业框架代码的时候发现当中 RPC 使用的是 Unix Socket,然后另一个被注释的实现是 TCP socket。就联想起 IPC 中的 Socket 方式。那么这三者究竟是怎样的关系呢?
[TOC]
Socket 通信
之前写过很原始的 TCP/UDP 通信,记得当时的代码大概是这个样子的:
1 | // create a socket |
- 首先创建一个 Socket, 其中 SOCK_STREAM 制定 socket 是一个 TCP socket。
- 绑定一个地址
- 开始监听地址
- accept 一个请求并处理
这是一个比较清晰的样例,其调用的是 linux 关于 socket 的系统调用。
Unix Socket
在做 MIT 6.824 时发现本地 RPC 走的是 Unix Sokcet,而不是原本我印象中的用于网络通信的 Socket。其代码大致如下
1 | l, e := net.Listen("unix", sockname) |
其通过一个 Socket 文件进行通信,会在 文件系统对应位置生成一个 .sock
文件。是不是很熟悉? 被 docker 折磨过的大概都记得 /var/run/docker.sock
文件吧,docker client 和 docker server 之间的通信方式就是通过 unix socket 协议。Unix socket 是一种很强大的 IPC 通信方式。
其系统调用过程如下:
1 | if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
和 TCP 的过程几乎一摸一样,区别在于 AF_UNIX。
那么 socket 和 unix socket 究竟有什么关系呢,或者说两者是不是一种东西?
tcp socket 和 unix socket 的比较
博客的解释:Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信。socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
知乎专栏则将其统一为一体:根据通信域的不同可以划分成2种:Unix domain socket 和 Internet domain socket。
stack overflow: 则从权限控制层次作为分析,Unix domain socket 没有经历网络,其更像是文件句柄,依赖文件系统的权限控制;而 TCP/UDP socket 则是网络层的概念,其经历网络的一系列操作后从报文层次(地址、端口等等)进行过滤
1 | raw answer: |
总结
总结一下:
- 我更倾向于知乎的一个回答,将 TCP socket 和 Unix scoket 结合在一起称作 socket,因为其系统调用 type 的区别而不同。即 socket 分为两种:Internet domain socket 和 Unix domain socket
- unix domain socket 层次更低一些,不涉及具体的网络操作,更像是文件句柄,受文件系统权限控制,也不包含网络解包等操作,所以在本地性能会更好一些。
- unix domain socket 不能进行跨主机通信,只能算是 IPC。