ipc

linux 进程间通讯

  • posix--system V:传统system v ipc受系统内核编译的资源限制,但移植方便。而posix受物理内存的限制,有文件权限要求,高效但可移植性差。
  • shm
    • 基于传统SYS V的共享内存
    • 基于POSIX mmap文件映射实现共享内存
    • 通过memfd_create()及fd跨进程实现共享内存
    • 基于dma-buf实现共享内存
  • pipe
  • fifo
  • msgq
  • semaphore
    • 基于传统SYS V信号量
    • 基于POSIX有名/无名信号量
  • signal
  • socket
  • notify/inotify
  • env
  • fork
  • mutex

操作

0.绪论

读写/转换/映射/拼接/拆分处理

1.I/O rw stream 函数api

ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict src_addr,
socklen_t *restrict addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

2.string处理 函数api

int sprintf(char *str, const char *format, ...); //将format格式字符串写入到str中,成功返回写入字符串长度,失败返回负数
int snprintf ( char * str, size_t size, const char * format, ... ); //将size-1长度的format格式字符串输入到str中,返回输入字符串的长度+1

shm 共享内存

1.SYS V函数api

int shmget(key_t key, size_t size, int shmflg); //创建/获取shm_id
void *shmat(int shm_id, const void *shm_addr, int shmflg); //通过唯一的shm_id映射shm的首地址
int shmdt(const void *shmaddr); //取消shm的映射
int shmctl(int shm_id, int command, struct shmid_ds *buf); //对shm进行控制(删除...)

2.POSIX mmap函数api

/*文件创建1*/
int access(const char* pathname, int mode);
int open(const char *pathname, int flags, mode_t mode); //路径自行指定,返回fd
/*文件创建2*/
int shm_open(const char *name, int oflag, mode_t mode); //以文件形式新建共享内存,返回fd,路径/dev/shm/
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); //将共享内存文件映射到进程中来,获取映射首地址
int msync ( void * addr, size_t len, int flags); //将进程内存中的数据同步到磁盘文件中
int munmap(void *addr, size_t length); //取消共享内存文件的进程映射
int shm_unlink(const char *name); //删除共享内存文件
int ftruncate(int fd, off_t length); //改变文件大小
int fstat(int fd, struct stat *buf); //获取文件属性

3.memfd_create()函数api

int memfd_create(const char *name, unsigned int flags);
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
int msync ( void * addr, size_t len, int flags);
int munmap(void *addr, size_t length);
int shm_unlink(const char *name);
int ftruncate(int fd, off_t length);

4.dma-buf函数api

kernel层封装对应的dma_buf_fd
int ioctl(int fd, int cmd, ...);
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
int munmap(void *addr, size_t length);
int shm_unlink(const char *name);
int ftruncate(int fd, off_t length);

pipe 匿名管道

1.函数api

FILE* popen(const char *command, const char *open_mode);
int pclose(FILE *stream_to_close);
int pipe(int file_descriptor[2]);
int dup(int file_descriptor);
int dup2(int file_descriptor_one, int file_descriptor_two);
int close(int fd);

fifo 命名管道

1.函数api

int mkfifo(const char *filename, mode_t mode);
int mknod(const char *filename, mode_t mode | S_IFIFO, (dev_t)0);
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

msgq 消息队列

1.SYS V函数api

//内核规定限制ipcs -l
// msgtype = 0--fifo;msgtype > 0--type类型的fifo;msgtype < 0
struct message {
    long int message_type;
    /* The data you wish to transfer */
};
int msgget(key_t, key, int msgflg); //创建msgq
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msg_sz); //向msgid发送消息,消息地址msg_ptr,长度msg_sz,msg_sz为0/IPC_NOWAIT阻塞或非阻塞
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);  //从msgid接收消息,存放地址msg_ptr,长度msg_st,队列类型msgtype,msgflg阻塞和非阻塞
int msgctl(int msgid, int command, struct msgid_ds *buf);

2.POSIX函数api

#include <mqueue.h>
struct mq_attr
{
  __syscall_slong_t mq_flags;	/* Message queue flags.0 or O_NONBLOCK  */
  __syscall_slong_t mq_maxmsg;	/* Maximum number of messages.  */
  __syscall_slong_t mq_msgsize;	/* Maximum message size.  */
  __syscall_slong_t mq_curmsgs;	/* Number of messages currently queued.  */
  __syscall_slong_t __pad[4];
};
mqd_t mq_open(const char *name, int oflag, ...); //新建消息队列文件
mqd_t mq_open(const char *name, int oflag, mode_t mode, mq_attr* attr); //name:/文件名; oflag:O_RDWR|O_CREAT; mode:0666; mq_attr:属性
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,unsigned msg_prio); //向msgq_id发送消息; 消息地址msg_ptr; 消息长度msg_len; 消息优先级msg_prio<MQ_PRIO_MAX
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); //从msgq_id接收消息; 存放地址msg_ptr; 接收长度msg_len; 消息优先级msg_prio<MQ_PRIO_MAX
mqd_t mq_unlink(const char *name); //删除消息队列文件
mqd_t mq_close(mqd_t mqdes);  //关闭msgq_id
int mq_notify(mqd_t mqdes, const struct sigevent *sevp); //消息队列异步通知回调
int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); //获取msg_id的属性
int mq_setattr(mqd_t mqdes, const struct mq_attr *restrict mqstat,struct mq_attr *restrict omqstat); //设置msg_id属性:新设置属性mqstat;旧属性omqstat
#define _XOPEN_SOURCE 600
#include <time.h>
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);  //发送超时限定
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);  //接收超时限定

semaphore 信号量

1.SYS V函数api

int semget(key_t key, int num_sems, int sem_flags); //进程间通讯使用,返回sem_id
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops); //进程间信号量控制
int semctl(int sem_id, int sem_num, int command, ...); //控制进程间的信号量

2.POSIX有名信号量函数api

sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value); //以文件的形式创建信号量并设置初值,方便进行进程间通讯
int sem_getvalue(sem_t *restrict sem, int *restrict sval); //获取信号量储存在sval,成功返回0或失败返回-1
int sem_wait(sem_t *sem); //信号量-1,信号量为0时,挂起阻塞等待
int sem_trywait(sem_t *sem); //信号量-1,信号量为0时,返回错误值,并继续执行
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); //信号量-1,信号量为0时作超时阻塞等待
int sem_post(sem_t *sem); //信号量+1
int sem_unlink(const char *name); //信号量文件删除
int sem_close(sem_t *sem); //信号量文件关闭

3.POSIX无名信号量函数api

int sem_init (sem_t *__sem, int __pshared, unsigned int __value); //初始化信号量值,返回成功0或失败-1
int sem_wait(sem_t *sem); //信号量-1,信号量为0时,挂起阻塞等待
int sem_trywait(sem_t *sem); //信号量-1,信号量为0时,返回错误值,并继续执行
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); //信号量-1,信号量为0时作超时阻塞等待
int sem_post(sem_t *sem); //信号量+1
int sem_destroy(sem_t *sem); //信号量销毁

signal 信号

1.POSIX 函数api

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);  //信号处理函数,signum需处理的信号编号,handler信号处理方式
void (*signal(int sig, void (*func)(int)))(int); //设置信号处理函数,sig设置指定信号编号处理信号的方式(SIG_DEF/SIG_IGN/...),func为回调函数
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
int sigemptyset(sigset_t *set); //将信号集初始化为空,成功返回0,失败返回-1
int sigfillset(sigset_t *set);  //将信号集初始化包含所有已定义的信号,成功返回0,失败返回-1
int sigaddset(sigset_t *set, int signo);  //将信号signo添加到信号集set中,成功返回0,失败返回-1
int sigdelset(sigset_t *set, int signo);  //将信号signo从信号集set删除,成功返回0,失败返回-1
int sigismember(sigset_t *set, int signo);  //判断signo是否为信号集set成员,成功返回0,失败返回-1
int sigpromask(int how, const sigset_t *set, sigset_t *oset); //对set信号集中的所有信号进行how设定,oset保留对set信号集how设置之前的信号集(SIG_BLOCK/SIG_UNBLOCK/SIG_SETMASK)
int sigpending(sigset_t *set); //读取当前进程中未处理信号集传递到set
int sigsuspend(const sigset_t *sigmask); //挂起等待接收信号集信号

2.SYS V 函数api

int sigwait(const sigset_t *set, int *sig); //同步的等待信号到来解除阻塞
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset); //屏蔽某个线程对某些信号的响应处理
int pthread_kill(pthread_t thread, int sig); //向某线程发送信号
int raise(int sig); //产生sig信号

socket 嵌套字

0.绪论

socket基本原理:int socket(int family, int type, int protocol);
family:协议簇定义ip:port地址
type:指定socket类型tcp udp raw
protocol:指定协议,在family需要指定特定协议时使用,eg:AF_INET TCP/UDP/IP/ICMP

1.函数api

/*数据流TCP*/
int socket(int domain, int type, int protocol);
int bind( int socket, const struct sockaddr *address, size_t address_len);
int listen(int socket, int backlog);
int accept(int socket, struct sockaddr *address, size_t *address_len);
int connect(int socket, const struct sockaddr *address, size_t address_len);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
int close(int fd);
/*数据报文UDP*/
int socket(int domain, int type, int protocol);
int bind( int socket, const struct sockaddr *address, size_t address_len);
int sendto(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *to, socklen_t tolen);
int recvfrom(int sockfd, void *buffer, size_t len,int flags, struct sockaddr *src_from, socklen_t *src_len); 
int close(int fd);

notify/inotify 文件扫描

1.函数api

int creat(const char *file,int auth);
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int remove(const char *filename);
int access(const char* pathname, int mode);
size_t strlen(const char *str);
char *strcpy(char *dest, const char *src);
char *strrchr(const char *str, int c);
int strncmp(const char *str1, const char *str2, size_t n);
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int mkdir(const char *path,mode_t mode);
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
struct dirent *readdir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
int closedir(DIR *dirp);
char *strcat(char *dest, const char *src);

env 环境变量

1.函数api

char *getenv(const char *name); //获取环境变量
int putenv(char *string); //设置环境变量
int setenv(const char *name, const char *value, int overwrite); //设置环境变量
int unsetenv(const char *name); //删除环境变量

pid 进程相关

0.绪论

fork函数会父子进程初始阶段共享所有数据(全局/栈区/堆区/代码),进行拷贝并隔离互不干扰执行。

1.函数api

pid_t fork(void); //在当前进程上创建一个子进程,子进程中返回值为0,小于0错误,父进程中返回子进程pid
pid_t getpid(void);  //获取当前进程pid
pid_t getppid(void);  //获取当前进程的父进程pid

mutex 互斥锁相关

0.绪论

程序段互斥锁上锁期间,程序阻塞CPU挂起,高并发过程中可减少CPU开支。

1.函数api

pthread_mutexattr_destroy(pthread_mutexattr_t *attr); //互斥锁属性销毁
int pthread_mutexattr_init(pthread_mutexattr_t *attr);  //初始化互斥锁属性
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
int pshared); //可设置进程间私有或公有属性
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *
restrict attr, int *restrict pshared);  //获取互斥锁属性的设置属性
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr,
                               int *robustness); //获取互斥锁的鲁棒属性
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr,
                               int robustness);//用于解决互斥锁所有者退出的锁状态问题
int pthread_mutex_destroy(pthread_mutex_t *mutex);  //销毁互斥锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr); //初始化互斥锁
int pthread_mutex_lock(pthread_mutex_t *mutex); //阻塞上锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);  //非阻塞上锁
int pthread_mutex_unlock(pthread_mutex_t *mutex); //解锁
    1. 以posix msgq + sysv msgq的形式,posix msgq设定消息队列的属性并以阻塞的形式去填充。需要俩个消息队列,posix msgq负责数据传递,sysv msgq负责消息指令传递。
    • 优点:指令和数据分离,结构清晰,实现简单,直接利用posix msgq及sysv msgq api,方便后期维护。
    • 缺点:仍然存在文件,docker端可能仍需解决文件权限问题,msgq的效率比shm效率稍低。
    1. 以sysv shm + sysv msgq的形式,和早上说的类似,将msg剥离出来分msgtype(@事件类型)来recv,进行对应的操作。
    • 优点:指令和数据分离,结构较为清晰,无文件,方便移植,效率较1.高
    • 缺点:指令较多会占用些许空间,指令分析处理较为复杂。
  • 对比原shm方案:
    • 优点:1.2.的cpu开销比较低。
    • 缺点:但sysv msgq的容量受系统限制,无连接的形式,安全性比较低。
    • 对比notify方案:2.为无文件IPC, 1.实现简单方便维护。
posted @ 2023-04-11 16:42  天纵之才  阅读(64)  评论(0)    收藏  举报