QQ,微信是我们早已熟悉不过的聊天软件,通过各种聊天软件,我们可以很愉快的和朋友开启聊天模式,其实,我们也可以自己制作一个聊天工具哦,下面就让我们通过有名管道+信号量的方式创建属于我们自己的聊天工具吧!
一、必备知识
- Linux基本操作命令
- C语言
- 进程的创建及相关操作
- 有名管道的创建及相关操作
- 信号通信
- 信号量
二、思路分析
- 创建两个用户,一个叫佩吉,一个叫斯基
- 两个用户创建有名管道
- 佩吉和斯基通过信号量交换彼此的进程pid号
- 佩吉和斯基通过共享通道实现聊天
- 当一个进程(即一个用户)按下ctrl+c,结束聊天
三、代码分析
创建两个文件,一个命名为pj.c,用于存放和佩吉相关的代码。
另外一个命名为sj.c,用于存放和斯基有关的代码。
1、pj.c
int fd;
int sj_pid;
void *addr;
void read_pid(int sig)
{
printf("斯基来信号了\n");
}
void readmsg(int sig)
{
printf("斯基说:%s\n",(char *)addr);
}
void stop(int sig)
{
//给斯基发个信号
kill(sj_pid,20);
//自己挂掉
exit(0);
}
void closeall(int sig)
{
exit(0);
}
int main(int argc,char *argv[])
{
if(argc!=2){
printf("usage:%s <fname>\n",argv[0]);
exit(-1);
}
//信号量
/* key */
key_t key = ftok("xx.c",5);
if(key<0){
perror("ftok error");
exit(-1);
}
printf("key :%#x\n",key);
/* semid */
int semid = semget(key,4,IPC_CREAT|0666);
if(semid<0){
perror("semget error");
exit(-1);
}
printf("semid:%d\n",semid);
//共享内存的
/* shmid */
int shmid = shmget(key,128,IPC_CREAT|0666);
if(shmid<0){
printf("shmget error\n");
exit(-1);
}
printf("shmid:%d\n",shmid);
/* shmat */
addr = shmat(shmid,NULL,0);
if(addr == (void *)-1){
perror("shmat error");
exit(-1);
}
//创建有名管道
if(access(argv[1],F_OK)){
if(mkfifo(argv[1],0666)){
perror("mkfifo error");
exit(-1);
}
}
//打开有名管道
fd = open(argv[1],O_RDWR);
if(fd<0){
perror("open error");
exit(-1);
}
//注册信号:
signal(3,read_pid);
/* 交换pid号 */
int pj_pid = getpid();
//写入 自己的
write(fd,&pj_pid,sizeof(pj_pid));
//******* 信号量p操作
struct sembuf ss = {0,-1,0};
int ret = semop(semid,&ss,1);
if(ret<0){
perror("semop error");
exit(-1);
}
//读取 对方的
read(fd,&sj_pid,sizeof(sj_pid));
printf("pj_pid:%d\n",pj_pid);
printf("sj_pid:%d\n",sj_pid);
signal(12,readmsg);
signal(2,stop);
signal(20,closeall);
/* 聊天 */
while(1){
scanf("%s",(char *)addr);
kill(sj_pid,10);
}
return 0;
}
2、sj.c
int fd;
int pj_pid;
void *addr;
void read_pid(int sig)
{
read(fd,&pj_pid,sizeof(pj_pid));
}
void readmsg(int sig)
{
printf("佩吉说:%s\n",(char *)addr);
}
void closeall(int sig)
{
exit(0);
}
void stop(int sig)
{
//给佩吉发送个信号
kill(pj_pid,20);
//自己挂掉
exit(0);
}
int main(int argc,char *argv[])
{
if(argc!=2){
printf("usage:%s <fname>\n",argv[0]);
exit(-1);
}
//信号量
/* key */
key_t key = ftok("xx.c",5);
if(key<0){
perror("ftok error");
exit(-1);
}
printf("key :%#x\n",key);
/* semid */
int semid = semget(key,4,IPC_CREAT|0666);
if(semid<0){
perror("semget error");
exit(-1);
}
printf("semid:%d\n",semid);
//共享内存的
/* shmid */
int shmid = shmget(key,128,IPC_CREAT|0666);
if(shmid<0){
printf("shmget error\n");
exit(-1);
}
printf("shmid:%d\n",shmid);
/* shmat */
addr = shmat(shmid,NULL,0);
if(addr == (void *)-1){
perror("shmat error");
exit(-1);
}
//创建有名管道
if(access(argv[1],F_OK)){
if(mkfifo(argv[1],0666)){
perror("mkfifo error");
exit(-1);
}
}
//打开有名管道
fd = open(argv[1],O_RDWR);
if(fd<0){
perror("open error");
exit(-1);
}
/* 交换pid号 */
int sj_pid = getpid();
//读取 对方的
read(fd,&pj_pid,sizeof(pj_pid));
//写入 自己的
write(fd,&sj_pid,sizeof(sj_pid));
//******* 信号量V操作
struct sembuf ss = {0,1,0};
int ret = semop(semid,&ss,1);
if(ret<0){
perror("semop error");
exit(-1);
}
printf("pj_pid:%d\n",pj_pid);
printf("sj_pid:%d\n",sj_pid);
signal(SIGUSR1,readmsg);
signal(SIGTSTP,closeall);
signal(SIGINT,stop);
/* 聊天 */
while(1){
scanf("%s",(char *)addr);
kill(pj_pid,12);
}
return 0;
}
四、参考书籍
刘洪涛,熊家.[嵌入式应用程序设计综合教程].北京:人民邮电出版社,2017.
刘洪涛,苗德行.[嵌入式 Linux C语言程序设计].北京:人民邮电出版社,2017