Skip to content

Unix域协议与多路复用

Unix域协议

Unix域协议是一种IPC(进程间通信) 方式,使用Socket编程接口实现本地进程间通信。其特点如下:

协议簇与套接字类型
  • 协议簇AF_UNIXAF_LOCAL(区别于 AF_INET IPv4)。
  • 套接字类型
    • SOCK_DGRAM:类似UDP的数据报套接字(无连接)。
    • SOCK_STREAM:类似TCP的流式套接字(面向连接)。
网络地址结构

使用文件系统路径作为地址(需以 \0 结尾):

c
#include <sys/un.h>  

struct sockaddr_un {  
    sa_family_t sun_family;    // 协议簇(AF_UNIX)  
    char sun_path[104];        // 套接字文件路径(如 "/tmp/xxx.socket")  
};
使用场景
  • 优势:数据不经过网卡,直接在内核中传输,效率高于IPv4协议。
  • 典型应用:本地进程间高速通信(如数据库守护进程与客户端交互)。

多路复用

多路复用用于同时监听多个文件描述符的就绪状态(可读/可写/异常),避免阻塞等待。

阻塞IO的局限性
  • 读操作:无数据时,read 会阻塞直到数据到达。
  • 写操作:无缓冲区空间时,write 会阻塞直到可写入。
1. select
c
#include <sys/select.h>  

int select(int nfds, fd_set *readfds, fd_set *writefds,  
          fd_set *exceptfds, struct timeval *timeout);
  • 参数
    • nfds:最大文件描述符值 + 1。
    • readfds/writefds/exceptfds:监听读/写/异常的描述符集合(传入需监听的描述符,返回就绪的描述符)。
    • timeout:超时时间(NULL 表示无限等待)。
  • 返回值
    • >0:就绪的描述符数量。
    • =0:超时。
    • <0:出错。
描述符集合操作函数
c
void FD_ZERO(fd_set *set);          // 清空集合  
void FD_SET(int fd, fd_set *set);   // 添加描述符到集合  
void FD_CLR(int fd, fd_set *set);   // 从集合移除描述符  
int FD_ISSET(int fd, fd_set *set);  // 检查描述符是否在集合中
2. poll
c
#include <poll.h>  

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • 参数
    • fdsstruct pollfd 结构体数组(每个元素描述一个监听请求)。
    • nfds:数组元素个数。
    • timeout:超时时间(毫秒)。
  • struct pollfd 结构
    c
    struct pollfd {  
        int fd;         // 文件描述符  
        short events;   // 监听的事件(如 POLLIN 可读、POLLOUT 可写)  
        short revents;  // 返回就绪的事件  
    };
  • 返回值:同 select
3. epoll(高效多路复用)
创建实例
c
#include <sys/epoll.h>  

int epoll_create(int size);  // size > 0(历史遗留,可忽略)  
// 成功返回 epoll 文件描述符,失败返回 -1
管理监听事件
c
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 参数
    • epfdepoll_create 返回的描述符。
    • op:操作类型(EPOLL_CTL_ADD 添加、EPOLL_CTL_DEL 删除、EPOLL_CTL_MOD 修改)。
    • fd:需监听的文件描述符。
    • event:监听事件结构体指针:
      c
      struct epoll_event {  
          uint32_t events;    // 监听事件(如 EPOLLIN、EPOLLOUT)  
          epoll_data_t data;  // 用户数据  
      };  
      
      typedef union epoll_data {  
          void *ptr;  
          int fd;  
          uint32_t u32;  
          uint64_t u64;  
      } epoll_data_t;
等待事件就绪
c
int epoll_wait(int epfd, struct epoll_event *events,  
               int maxevents, int timeout);
  • 参数
    • events:输出参数,存储就绪事件的结构体数组。
    • maxevents:数组最大容量。
    • timeout:超时时间(毫秒)。
  • 返回值:同 select
触发模式
  • 水平触发(LT)
    • 只要描述符就绪,持续上报事件(默认模式)。
  • 边缘触发(ET)
    • 仅在状态变化时上报一次事件(需设置 EPOLLET 标志)。
效率对比
机制效率特点
select低(O(n)轮询)支持文件描述符数量有限(通常1024)
poll中(O(n)轮询)无描述符数量限制
epoll高(O(1)事件通知)支持边缘触发,适合高并发场景

总结

  • Unix域协议:通过文件路径标识地址,实现本地进程间高效通信。
  • 多路复用
    • select/poll:适用于少量描述符监听。
    • epoll:适用于高并发场景,支持边缘触发模式。

知识如风,常伴吾身