zzLINUX信号通信---不同进程间发送与接收携带字符串的信号(使用共享内存机制)_sigaction如何接收字符串-CSDN博客
问题的发现:不同进程如何传字符串
上面的博文中也提出了一样的问题
在学习信号的时候我曾在不同进程之间通过sigqueue和sigaction传递整型,然后尝试传递字符串的时候一直出现段错误
程序和实验结果如下:
下面是接收端的程序:
#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
// int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
/*调用handler函数之后先打印信号的值,打印完之后判断携带的内容是否为空,非空的话打印info中的si_int,
*/
void handler(int signum,siginfo_t *info,void *context)
{
printf("get signum = %d\n",signum);
if(context != NULL)//判断携带内容是否为空
{
printf("the pid is:%d\n",getpid());
printf("get data:%s\n",(char *)info->si_ptr);
}
}
int main()
{
struct sigaction act;
act.sa_sigaction = handler;//收到信号之后调用handler处理信号
act.sa_flags = SA_SIGINFO;//必须指定,以能够获得数据
sigaction(SIGUSR1,&act,NULL);
while(1);
return 0;
}
这是发送端的程序:
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
int main(int argc,char **argv)
{
int signum;
int pid;
char *p ="zcy,cool!";
signum = atoi(argv[1]);
pid = atoi(argv[2]);
union sigval value;
value.sival_ptr = p;
// int sigqueue(pid_t pid, int sig, const union sigval value);
sigqueue(pid,signum,value);
printf("传输内容:%p\n",value.sival_ptr);
return 0;
}
~
但是当我打印发送和接受的字符串地址的时候确实可以正常打印,这说明数据确实传过去了,但是一旦强制类型转换然后 %s 输出成字符串就会出现段错误
打印地址时的结果:
打印字符串时的结果:
于是我又找到了这篇博文讲得很好,本质原因就是不同进程之间传递字符串必须要用 共享内存 来传递。
尝试通过共享内存解决问题
下面我尝试创建一个共享内存区域然后传递一下字符串试试:
老样子,先说结论:实验成功了
因为我叫zcy,所以自恋传了个我真帅
这个程序本质其实就是如何结合共享内存和不同进程传递函数sigaction及sigqueue:
思路如下:
我需要写两个进程:分别是接收进程和发送进程
发送进程:
1、创建key值
2、通过key创建共享内存
3、定义好sigqueue函数需要的参数
4、将sigqueue函数中的联合体结构的void类型指针与共享内存连接起来,这样我往指针中传字符串,也会写到共享内存中
接收进程:
1、创建相同的key值
2、通过key值连接共享内存
3、定义好sigaction所需要的各个参数
4、连接sigaction中的info_t类型结构体中的void类型指针与共享内存连接起来,这样我可以直接读取该指针中的内容,需要注意强制类型转换
下面是发送进程的程序:
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
int main(int argc,char **argv)
{
char *src = "zcy,cool!";
int signum;
int pid;
union sigval value;
//创建一个key值
int key = ftok(".",3);
if(key == -1)
{
printf("ftok failed\n");
perror("ftok");
exit(-1);
}
printf("key:%d\n",key);
//创建共享内存
int shm_id = shmget(key,1024,IPC_CREAT|0777);
if(shm_id == -1)
{
printf("shmget failed\n");
perror("shmget");
exit(-1);
}else
printf("shmget success\n");
//连接共享内存(重点)
value.sival_ptr=(void *)shmat(shm_id,0,0);
if(value.sival_ptr == (void *)-1)
{
printf("shmat failed\n");
perror("shmat");
}else
printf("shmat success\n");
//往共享内存中传字符串
strcpy(value.sival_ptr,src);
printf("strcpy success\n");
signum = atoi(argv[1]);
pid = atoi(argv[2]);
// int sigqueue(pid_t pid, int sig, const union sigval value);
sigqueue(pid,signum,value);
printf("传输内容:%p\n",value.sival_ptr);
return 0;
}
下面是接收进程的程序:
#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
// int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
/*调用handler函数之后先打印信号的值,打印完之后判断携带的内容是否为空,非空的话打印info中的si_int,
*/
//信号处理函数
void handler(int signum,siginfo_t *info,void *context)
{
//创建同一个key值
key_t key;
key = ftok(".",3);
//连接共享内存
int shm_id = shmget(key,1024,0);
if(shm_id == -1)
{
printf("shemget failed\n");
perror("shmget");
exit(-1);
}else
printf("shmget success\n");
//连接共享内存(重点)
info->si_ptr =(void *) shmat(shm_id,0,0);
if(info->si_ptr == (void *)-1)
{
printf("shmat failed\n");
perror("shmat");
}else
printf("shmat success\n");
printf("get signum = %d\n",signum);
if(context != NULL)//判断携带内容是否为空
{
printf("the pid is:%d\n",getpid());
printf("get data:%s\n",(char *)info->si_ptr);
}
}
int main()
{
struct sigaction act;
act.sa_sigaction = handler;//收到信号之后调用handler处理信号
act.sa_flags = SA_SIGINFO;//必须指定,以能够获得数据
sigaction(SIGUSR1,&act,NULL);
while(1);
return 0;
}
如果你掌握了sigaction和sigqueue函数的基本用法以及如何创建连接共享内存的方法,上面的代码还是比较好理解的,我个人觉得最头疼的还是sigaction函数中有太多的参数,而且我还没完全搞懂每个参数那么多选择的用法都是什么,只掌握了基本的使用方法,本文只是我刚入门这一块的一段历程,如有误请各位大佬多多指正,谢谢!