Unix域套接字
Unix域套接字
Unix域套接字是非常有用的IPC机制,接口上使用socket API,和TCP/IP,UDP/IP保持一致,随时可以相互切换,但是Unix域套接字并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文,因此要高效的多。相比其他IPC机制(管道,共享内存),它有下面的特点:
1. 相比网络传输它更安全,因为只能在本机使用,所以又称Unix local socket;
2. 并不依赖网络支持,不需要任何网络环境和参数配置;
3. 是全双工的;
4. 既支持面向连接的(steam)流式通讯,又支持面向无连接的(datagram)socket通讯;
5. 相比其他IPC方式更安全:
* 服务端通过设置绑定的文件的文件权限(主要是应用umask调用)可以限制特定用户或组进行连接;
* 因为Unix域套接字整个流程都发生在同一个系统上,该系统内核因此知道连接端和被连接端双端的一切事情。这意味着服务端可以通过系统调用获知连上来的客户端的一些信息例如用户id,用户组id,进程id,服务端可以依据这些来对相应客户端进行授权。
6. 打开的文件描述符可以可以通过Unix域套接字在一个进程到另一个进程之间传递;
认证服务器
前面有说内核是知道Unix域套接字的连接双方的,于是可以在服务端通过这样的系统调用来获取客户端的凭证(UID,GID,PID),进而进行权限认证,从而达到客户端权限控制。这个系统调用就是通用的getsockopt,具体代码如下(注意并不是每一个平台支持以下的代码):
struct ucred credentials; int ucred_length = sizeof(struct ucred); /* fill in the user data structure */ if(getsockopt(connection_fd, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) { printf("could obtain credentials from unix domain socket"); return 1; } /* the process ID of the process on the other side of the socket */ credentials.pid; /* the effective UID of the process on the other side of the socket */ credentials.uid; /* the effective primary GID of the process on the other side of the socket */ credentials.gid; /* To get supplemental groups, we will have to look them up in our account database, after a reverse lookup on the UID to get the account name. We can take this opportunity to check to see if this is a legit account. */
文件描述符传递
文件描述符传递绝不是只是把一个数值的文件描述符号从一个进程传递到另一个进程,而是如下图所示,接收进程可能使用了一个不同的文件描述符号,但是指向了同一个文件表项,也就是两个进程共享该文件的状态标志,当前偏移量。其实实际中文件描述符传递用的比较少,具体用法在文档中有清晰描述就不再复述。