socket,大家可能都比较熟悉,通常指的是 network socket,或者 Internet Socket(IP Socket),是 unix 网络编程的基础概念。
了解网络编程的开发人员在选择进程间通信机制时,一般都倾向于 IP sockets over localhost,即在回路(loopback)接口地址上,更不讲究的,就会使用内网地址,其通信机制就是一个典型、完整的网络通信。
本文介绍一下 Unix domain socket,也叫 IPC socket (inter-process communication socket),即进程间通信 socket,这种机制和网络通信在本质上是完全不同的,只不过在形式上有些相似。
Socket - Client Server Model
- 这篇文章讲解了 socket 的基本原理;
- 这篇文章准确的命名应当是 network socket;
- Beej's Guide to Network Programming - Using Internet Sockets;
UNIX domain sockets
- Unix Sockets 通常指的就是 UNIX domain sockets;
client 端的过程
- socket()
client 创建一个 socket。
socket() 函数返回一个 socket descriptor。单独一个 socket 没什么用,需要将这个 socket 用在后续的系统调用里,比如 bind() 就有用了。 - bind()
将 socket 绑定到本机一个文件 cfile,这个文件可以理解为网络编程中的IP和端口port;
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sockfd is the socket file descriptor returned by socket(). my_addr is a pointer to a struct sockaddr that contains information about your address, namely, port and IP address.
把一个 socket 绑到 IP和port(网络编程),或者本机的一个文件上(IPC 通信),都是一个地址,别人能据此找到你。
在网络编程中,client 端通常不需要显性 bind(),即使 bind,在 bind 中也不显性指定端口号,而由系统自主处理,因为我们并不关心本地的 port 端口号;对于 Unix domain socket,如果你需要双向通信,则 client 需要 bind。 - connect()
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
客户端连接服务器,其中 sockfd 就是你创建的那个 socket(已经绑定了 cfile),serv_addr 是 server 端的地址(结构中指定了服务器所绑定的文件 sfile,这个文件是客户端和服务端都需要事先知道的,而 cfile 不需要事先告知 server 端); - send()
int send(int sockfd, const void *msg, int len, int flags); - recv()
int recv(int sockfd, void *buf, int len, int flags);
内核侦测到有数据写入 cfile 这个文件管道后(server 写入到 cfile),通过 socket 传送给 client 进程。 - 进程接收到数据
server 端的过程
- socket()
- bind()
- recvfrom()
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
如果 cfile 没有事先告知服务器,则服务器要首先从 recvfrom 的 from 参数(recvfrom 函数调用后 from 参数会被赋值)获知客户端的 cfile,再 sendto,从而实现双向通信。 - sendto()
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, socklen_t tolen);