- 信号
- 管道
- 命名管道
- 信号量(system V)
- 消息队列
- 共享内存
- 内存映射文件
- 套接字
1. 信号
信号是UNIX和Linux系统响应某些条件而产生的一个事件。接收到该信号的进程会采取相应的行动。
在此列出几个简单使用方法定义:
#include <sys/types.h>
#include <signal.h>
void (*signal(int sig,void (*func)(int)))(int);
int kill(pid_t pid,int sig);
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
int pause(void);
由于signal不够健壮,推荐使用sigaction函数。
2. 管道
管道主要用于具有亲缘关系的进程间通信,允许一个进程和另一个与它有共同祖先的进程通信。比如fork或exec创建的新进程。在使用exec创建新进程时,需要将管道的文件描述符作为参数传递给exec创建的新进程。
pipe函数原型:
#include <unistd.h>
int pipe(int file_descriptor[2]);
该函数在数组上填上两个新的文件描述符后返回0,失败返回-1。
通过使用底层的read和write调用来访问数据。
向file_descriptor[1]写数据,从file_descriptor[0]中读数据。写入与读取的顺序原则是先进先出。
3. 命名管道
命名管道是一种特殊类型的文件,它在系统中以文件形式存在。这样克服了管道的弊端,他可以允许没有亲缘关系的进程间通信。
创建管道的两个系统调用原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename,mode_t mode);
int mknod(const char *filename,mode_t mode|S_IFIFO,(dev_t) 0);
具体操作方法只要创建了一个命名管道然后就可以使用open、read、write等系统调用来操作。创建可以手工创建或者程序中创建。
4. 信号量(system V)
信号量主要用于管理不同进程对资源的访问。
信号量是特殊的变量,它只取正整数值并且只允许对这个值进行两种操作:等待(wait)和信号(signal)。(P、V操作,P用于等待,V用于信号)
p(sv):如果sv的值大于0,就给它减1;如果它的值等于0,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行;如果没有其他进程因等待sv而挂起,则给它加1
简单理解就是P相当于申请资源,V相当于释放资源
信号量函数定义:
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sem.h>
int semctl(int sem_id,int sem_num,int command,...);
int semget(key_t key,int num_sems,int sem_flags);
int semop(int sem_id,struct sembuf *sem_ops,size_t num_sem_ops);
semctl函数用于控制信号量,初始化信号量的值,删除一个信号量等。
semget函数用于创建一个新的信号量或者取得一个已有信号量的键。
semop函数用于改变信号量的值,一般是加1或减1,及PV操作。
不同进程只要key值相同即可访问同一信号量。
5. 消息队列
消息队列是消息的链接表,可向其中添加信息,或者从其中读取信息。
消息队列克服了信号承载信息量少,管道只能承载无格式字符流。
消息队列函数定义:
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
int msgget(key_t key,int msgflag);
int msgrcv(int msgid,void *msgptr,size_t msg_sz,long int msgtype,int
msgflg);
int msgsnd(int msgid,const void *msgptr,size_t msg_sz,int msgflg);
msgget用来创建和访问一个消息队列。程序必须提供一个键值来命名特定的消息队列。
msgsend函数允许我们把一条消息添加到消息队列中。msgptr只想准备发送消息的指针,指针结构体必须以一个长整型变量开始。
msgrcv函数从一个消息队列中获取消息。成功时msgrcv函数返回放到接收缓冲区的字节数,消息被拷贝到msgptr指向的用户分配的缓冲区中,然后删除消息队列中的对于消息。
msgctl函数主要是一些控制如删除消息队列等操作。
6. 共享内存
共享内存是由IPC为进程创建的一个特殊地址范围,它将出现在该进程的地址空间中。其他进程可以将同一段共享内存连接到自己的地址空间中。所有内存都可以访问共享内存中的地址,就好像它们是malloc分配的一样。如果一个进程向共享内存中写入了数据,所做的改动将立刻被其他进程看到。
共享内存本身并没有同步机制,需要程序员自己控制。
共享内存函数定义:
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
void *shmat(int shm_id,const void *shm_addr,int shmflg);
int shmctl(int shm_id,int cmd,struct shmid_ds *buf);
int shmdt(const void *shm_addr);
int shmget(key_t key,size_t size,int shmflg);
shmget函数用来创建共享内存。
shmat函数将共享内存连接到进程的地址空间中。
shmdt函数将共享内存从当前进程中分离。
shmctl函数是控制函数,比如删除共享内存操作。
7. 内存映射文件
内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
#include <sys.mman.h>
void *mmap(void*start,size_t length,int prot,int flags,int fd,off_t
offset);
int munmap(void* start,size_t length);
int msync(void *addr,size_t len,int flags);
mmap函数将一个文件或者其它对象映射进内存。
munmap函数解除内存映射。
msync函数将内存数据写入到文件或者从文件读取数据。
8. 套接字
套接字机制不但可以单机的不同进程通信,而且使得跨网机器间进程可以通信。
套接字的创建和使用与管道是有区别的,套接字明确地将客户端与服务器区分开来,套接字可以实现多个客户端连到同一服务器。
服务器套接字连接过程描述:
首先,服务器应用程序用socket创建一个套接字,它是系统分配服务器进程的类似文件描述符的资源。
接着,服务器调用bind给套接字命名。这个名字是一个标示符,它允许linux将进入的针对特定端口的连接转到正确的服务器进程。
然后,系统调用listen函数开始接听,等待客户端连接。listen创建一个队列并将其用于存放来自客户端的进入连接。
当客户端调用connect请求连接时,服务器调用accept接受客户端连接,accept此时会创建一个新套接字,用于与这个客户端进行通信。
客户端套接字连接过程描述:
客户端首先调用socket创建一个未命名套接字,让后将服务器的命名套接字作为地址来调用connect与服务器建立连接。
只要双方连接建立成功,我们就可以像操作底层文件一样来操作socket套接字实现通信。
几个基础函数定义:
#include <sys/types.h>
#include <sys/socket.h>
int socket(it domain,int type,int protocal);
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 *addrsss,size_t address_len);
函数介绍如上过程描述。