15.信号通信编程

在Linux系统中,信号signal的通信机制。

信号处理流程:

????

从上面的图可以清楚的看出信号处理的一般流程:1.选择信号 2.发送信号 3.处理信号。

信号的类型:Linux系统支持的所有信号均定义在/usr/include/asm/signal.h里面,其中常见的信号有:

????SIGKILL:杀死进程

????SIGSTOP:暂停进程

????SIGCHLD:子进程停止或者结束时用来通知父进程。

?

杀死进程:

查看信息:man 2 kill:

NAME

kill - send signal to a process

?

SYNOPSIS

#include <sys/types.h>

#include <signal.h>

?

int kill(pid_t pid, int sig);

?

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

?

kill(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

?

DESCRIPTION

The kill() system call can be used to send any signal to any process

group or process.

?

If pid is positive, then signal sig is sent to the process with the ID

specified by pid.

?

If pid equals 0, then sig is sent to every process in the process group

of the calling process.

?

If pid equals -1, then sig is sent to every process for which the call-

ing process has permission to send signals, except for process 1

(init), but see below.

If pid is less than -1, then sig is sent to every process in the pro-

cess group whose ID is -pid.

?

If sig is 0, then no signal is sent, but error checking is still per-

formed; this can be used to check for the existence of a process ID or

process group ID.

?

For a process to have permission to send a signal it must either be

privileged (under Linux: have the CAP_KILL capability), or the real or

effective user ID of the sending process must equal the real or saved

set-user-ID of the target process. In the case of SIGCONT it suffices

when the sending and receiving processes belong to the same session.

?

RETURN VALUE

On success (at least one signal was sent), zero is returned. On error,

-1 is returned, and errno is set appropriately.

?

ERRORS

EINVAL An invalid signal was specified.

?

EPERM The process does not have permission to send the signal to any

of the target processes.

?

ESRCH The pid or process group does not exist. Note that an existing

process might be a zombie, a process which already committed

termination, but has not yet been wait(2)ed for.

CONFORMING TO

SVr4, 4.3BSD, POSIX.1-2001.

?

NOTES

The only signals that can be sent to process ID 1, the init process,

are those for which init has explicitly installed signal handlers.

This is done to assure the system is not brought down accidentally.

?

POSIX.1-2001 requires that kill(-1,sig) send sig to all processes that

the calling process may send signals to, except possibly for some

implementation-defined system processes. Linux allows a process to

signal itself, but on Linux the call kill(-1,sig) does not signal the

calling process.

?

POSIX.1-2001 requires that if a process sends a signal to itself, and

the sending thread does not have the signal blocked, and no other

thread has it unblocked or is waiting for it in sigwait(3), at least

one unblocked signal must be delivered to the sending thread before the

kill().

?

Linux Notes

Across different kernel versions, Linux has enforced different rules

for the permissions required for an unprivileged process to send a sig-

nal to another process. In kernels 1.0 to 1.2.2, a signal could be

sent if the effective user ID of the sender matched that of the

receiver, or the real user ID of the sender matched that of the

receiver. From kernel 1.2.3 until 1.3.77, a signal could be sent if

the effective user ID of the sender matched either the real or effec-

tive user ID of the receiver. The current rules, which conform to

POSIX.1-2001, were adopted in kernel 1.3.78.

?

BUGS

In 2.6 kernels up to and including 2.6.7, there was a bug that meant

that when sending signals to a process group, kill() failed with the

error EPERM if the caller did have permission to send the signal to any

(rather than all) of the members of the process group. Notwithstanding

this error return, the signal was still delivered to all of the pro-

cesses for which the caller had permission to signal.

?

SEE ALSO

_exit(2), killpg(2), signal(2), sigqueue(2), tkill(2), exit(3), capa-

bilities(7), credentials(7), signal(7)

?

COLOPHON

This page is part of release 3.22 of the Linux man-pages project. A

description of the project, and information about reporting bugs, can

be found at http://www.kernel.org/doc/man-pages/.

Kill的函数原型:

int kill(pid_t pid, int sig);

需要包含的头文件:

#include <sys/types.h>

#include <signal.h>

该函数的功能是向进程发送信号。

返回值:成功返回0,失败返回-1.

参数说明:

Pid:pid>0,pid参数指向接受信号的进程,pid=0表示向同组的进程发送信号。如果pid=-1则表示进程的信号将发送给所有拥有权限的线程。除了init线程。如果pid<-1,则发送给同组的进程为pid的进程。如果sig=0,则表示没有信心传递。

?

Sig:指向要发送的信号

?

?

信号:

查看信息:

NAME

signal - ANSI C signal handling

?

SYNOPSIS

#include <signal.h>

?

typedef void (*sighandler_t)(int);

?

sighandler_t signal(int signum, sighandler_t handler);

?

DESCRIPTION

The behavior of signal() varies across Unix versions, and has also varied his-

torically across different versions of Linux. Avoid its use: use sigaction(2)

instead. See Portability below.

?

signal() sets the disposition of the signal signum to handler, which is either

SIG_IGN, SIG_DFL, or the address of a programmer-defined function (a "signal

handler").

?

If the signal signum is delivered to the process, then one of the following

happens:

?

* If the disposition is set to SIG_IGN, then the signal is ignored.

?

* If the disposition is set to SIG_DFL, then the default action associated

with the signal (see signal(7)) occurs.

* If the disposition is set to a function, then first either the disposition

is reset to SIG_DFL, or the signal is blocked (see Portability below), and

then handler is called with argument signum. If invocation of the handler

caused the signal to be blocked, then the signal is unblocked upon return

from the handler.

?

The signals SIGKILL and SIGSTOP cannot be caught or ignored.

?

RETURN VALUE

signal() returns the previous value of the signal handler, or SIG_ERR on error.

?

ERRORS

EINVAL signum is invalid.

?

CONFORMING TO

C89, C99, POSIX.1-2001.

?

NOTES

The effects of signal() in a multithreaded process are unspecified.

?

According to POSIX, the behavior of a process is undefined after it ignores a

SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or

raise(3). Integer division by zero has undefined result. On some architec-

tures it will generate a SIGFPE signal. (Also dividing the most negative inte-

ger by -1 may generate SIGFPE.) Ignoring this signal might lead to an endless

loop.

See sigaction(2) for details on what happens when SIGCHLD is set to SIG_IGN.

?

See signal(7) for a list of the async-signal-safe functions that can be safely

called from inside a signal handler.

?

The use of sighandler_t is a GNU extension. Various versions of libc predefine

this type; libc4 and libc5 define SignalHandler; glibc defines sig_t and, when

_GNU_SOURCE is defined, also sighandler_t. Without use of such a type, the

declaration of signal() is the somewhat harder to read:

?

void ( *signal(int signum, void (*handler)(int)) ) (int);

?

Portability

The only portable use of signal() is to set a signal‘s disposition to SIG_DFL

or SIG_IGN. The semantics when using signal() to establish a signal handler

vary across systems (and POSIX.1 explicitly permits this variation); do not use

it for this purpose.

?

POSIX.1 solved the portability mess by specifying sigaction(2), which provides

explicit control of the semantics when a signal handler is invoked; use that

interface instead of signal().

?

In the original Unix systems, when a handler that was established using sig-

nal() was invoked by the delivery of a signal, the disposition of the signal

would be reset to SIG_DFL, and the system did not block delivery of further

instances of the signal. System V also provides these semantics for signal().

This was bad because the signal might be delivered again before the handler had

a chance to reestablish itself. Furthermore, rapid deliveries of the same sig-

nal could result in recursive invocations of the handler.

?

BSD improved on this situation by changing the semantics of signal handling

(but, unfortunately, silently changed the semantics when establishing a handler

with signal()). On BSD, when a signal handler is invoked, the signal disposi-

tion is not reset, and further instances of the signal are blocked from being

delivered while the handler is executing.

?

The situation on Linux is as follows:

?

* The kernel‘s signal() system call provides System V semantics.

?

* By default, in glibc 2 and later, the signal() wrapper function does not

invoke the kernel system call. Instead, it calls sigaction(2) using flags

that supply BSD semantics. This default behavior is provided as long as the

_BSD_SOURCE feature test macro is defined. By default, _BSD_SOURCE is

defined; it is also implicitly defined if one defines _GNU_SOURCE, and can of

course be explicitly defined.

?

On glibc 2 and later, if the _BSD_SOURCE feature test macro is not defined,

then signal() provides System V semantics. (The default implicit definition

of _BSD_SOURCE is not provided if one invokes gcc(1) in one of its standard

modes (-std=xxx or -ansi) or defines various other feature test macros such

as _POSIX_SOURCE, _XOPEN_SOURCE, or _SVID_SOURCE; see fea-

ture_test_macros(7).)

* The signal() function in Linux libc4 and libc5 provide System V semantics.

If one on a libc5 system includes <bsd/signal.h> instead of <signal.h>, then

signal() provides BSD semantics.

?

SEE ALSO

kill(1), alarm(2), kill(2), killpg(2), pause(2), sigaction(2), signalfd(2),

sigpending(2), sigprocmask(2), sigqueue(2), sigsuspend(2), bsd_signal(3),

raise(3), siginterrupt(3), sigsetops(3), sigvec(3), sysv_signal(3), fea-

ture_test_macros(7), signal(7)

?

COLOPHON

This page is part of release 3.22 of the Linux man-pages project. A descrip-

tion of the project, and information about reporting bugs, can be found at

http://www.kernel.org/doc/man-pages/.

函数名:signal。

函数原型:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

该函数的功能:设置信号的处理方式。

需要的头文件:signal.h

返回值:成功:返回处理函数指针。失败:返回SIG_ERR.

参数:

Signum:要处理的信号。

Handler:对应信号的处理方式,可以取值:

????SIG_IGN:忽视这个信号,不处理。

????SIG_DFL:交给内核来处理。

????用户自定义的函数:自己定义函数来处理:typedef void (*sighandler_t)(int);

?

?

暂停信号:

函数的原型pause:

查看文档:

NAME

pause - wait for signal

?

SYNOPSIS

#include <unistd.h>

?

int pause(void);

?

DESCRIPTION

pause() causes the calling process (or thread) to sleep until a signal

is delivered that either terminates the process or causes the invoca-

tion of a signal-catching function.

?

RETURN VALUE

pause() only returns when a signal was caught and the signal-catching

function returned. In this case pause() returns -1, and errno is set

to EINTR.

?

ERRORS

EINTR a signal was caught and the signal-catching function returned.

?

CONFORMING TO

SVr4, 4.3BSD, POSIX.1-2001.

?

SEE ALSO

kill(2), select(2), signal(2), sigsuspend(2)

?

COLOPHON

This page is part of release 3.22 of the Linux man-pages project. A

description of the project, and information about reporting bugs, can

be found at http://www.kernel.org/doc/man-pages/.

该函数的原型:

int pause(void);

该函数没有参数,功能是等待一个进程,直到收到信号。

?

?

下面我们来实现:A,B进程通信的机制。

A进程:发送signal到B进程。

B进程:B进程设置signal信号的处理方式,然后等待。

?

编写B:asignal.c接受来之A的信号:

asignal.c:

#include <signal.h>

#include <unistd.h>

void myfunc(int a){

????printf("process B received signal!\n");

}

void main(){

?

????signal(SIGINT,myfunc);

????pause();

}

编译运行:

运行完后进入等待状态。

然后在命令行发送一个信号:

先执行ps aux:

知道进程号为3588.

然后在另外一个终端执行:

应用程序收到信号:

我们看到进程收到了信号输出了信息。

?

?

接下来我们来编写A程序:aasignal.c:

#include <sys/types.h>

#include <signal.h>

#include <stdio.h>

?

void main(int argc, char **argv){

????pid_t pid;

????pid = atoi(argv[1]);//change string to integer

????kill(pid,SIGINT);

}

?

运行的结果:

通过上面的例子我们知道:当我们运行了A进程后,B进程收到了信号,打印出来了信息。并且我们在A进程进行了自行出理。这样我们就可以实现进程间的通信机制了。

时间: 2024-10-06 06:55:36

15.信号通信编程的相关文章

【转载】15年编程生涯,资深架构师总结的7条经验

原文:15年编程生涯,资深架构师总结的7条经验 前言: 这是一篇应InfoQ之邀写的文章, 首发在InfoQ微信公共号上. 大家有空可以多看看InfoQ 网站和公共号 , 是个很有深度的优秀社区. 我和很多人交流过一个有趣的现象,那就是刚毕业到30岁这段时间,会觉得时间过得很慢,总觉得自己还很年轻,但是一旦过了30岁,时间就如白驹过隙,一年又一年飞逝而过. 我自己也是,眼瞅着毕业快15年了,15年间从一个刚毕业的菜鸟,成长为技术骨干,做到架构师的职位,回头看看,当年听取亲戚的一句话,误入计算机行

15个编程好习惯

编者按:这是国外程序员Al katib总结的一些编程习惯. 1. 动手编码之前,你需要对要编码实现的解决方案有一个正式的或粗略的设计.永远不要在没有任何设计的前提下就开始编码,除非所编代码不重要. 2. 优秀的代码文档跟编程语言知识一样重要.在代码源文件中,为每个主要的代码段添加注释,解释代码的基本逻辑.最好注明程序的构建和修改日期,以及修改的原因也是非常有必要的. 3. 维护程序的各个版本同样重要.当前有些编程工具都自带一个版本管理工具.无论你什么时候改变自己的程序,它们都会将其保存为.bak

软件工程网络15结对编程作业

Deadline: 2018-3-25 10:00PM,以提交至班级博客时间为准. 请在两周时间内完成结对编程练习,注意时间的合理安排. 参考来自http://www.cnblogs.com/xinz/p/7417960.html 题目要求: 1.改进现有代码 分析网络14部分现有程序代码(请选择其中一个) 个人博客地址1:http://www.cnblogs.com/weihui-01 ,源代码:https://coding.net/u/weh/p/software-testing/git 个

软工网络15结对编程练习(201521123007谭燕)

链接 学号:201521123006:博客链接: http://www.cnblogs.com/KimHeechul/p/8644402.html 学号:201521123007:博客链接: http://www.cnblogs.com/ty1213/p/8644960.html 码云地址: https://gitee.com/KimHeechul/pair_programming/commits/master 题目要求: 1. 改进现有代码 1.1 分析网络14部分现有程序代码 个人博客地址4

软工网络15结对编程练习 201521123056 吴剑通

0.结对编程成员: 吴剑通博客地址:https://www.cnblogs.com/wjt960310/ 杨均宇博客地址:http://www.cnblogs.com/GOB8023/ 码云地址:https://gitee.com/jmu201521123056/four_operations 源代码:https://coding.net/u/Belong033/p/java-third/git 原题目要求 http://www.cnblogs.com/happyzm/p/6472120.htm

软件工程网络15结对编程作业(201521123062)

0.结对编程成员: 吴剑通博客地址:https://www.cnblogs.com/wjt960310/ 杨钧宇博客地址:http://www.cnblogs.com/GOB8023/ 码云地址:https://gitee.com/jmu201521123056/four_operations 源代码:https://coding.net/u/Belong033/p/java-third/git 原题目要求 http://www.cnblogs.com/happyzm/p/6472120.htm

2016.9.15 黑客编程之无限启动

1.涉及的编程工具是:VS2013:可以在windows环境下,编写web,JavaScript,C++,C等等程序: 2.第一个需要掌握的函数是:ExitWindowsEx(EWX_REBOOT, 0);该函数用来重启,关闭,注销电脑: 3.使用该函数必须先,包含windows的API: #include <windows.h> 4.权限问题,代码解决: BOOL MySystemShutdown(){ HANDLE hToken; TOKEN_PRIVILEGES tkp; // Get

2016.12.15网络编程学习笔记

---恢复内容开始--- TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip地址"可以唯一标识网络中的主机,而传输层的"协议+端口"可以唯一标识主机中的应用程序(进程).利用三元组(ip地址,协议,端口)就可以标识网络的进程.TCP/IP协议的应用程序通常采用应用编程接口:UNIX  BSD的套接字(socket),来实现网络进程之间的通信,网络中进程通信是无处不在,这就是我为什么说"一切皆socket".socket起源于Unix,而U

2017-12-5Linux基础知识(15)shell编程

shell编程是在Linux的基础知识中所必须掌握的语言,它也是一个命令的集合,如果学会的话,我们将会事半功倍,将重复的操作通过shell编程脚本来实现,减轻了一定的负担,那么现在就来讲一下shell编程的基础. 一.编程语言的分类 其实根据其语言的分类来讲,强类型的编程语言首先要编译成为该平台的二进制程序文件所能运行,当程序文件可以运行时,编译器就不在参与,而在弱类型的编程语言当中,使用解释器将源代码边解释边执行,那么相当于前者来说,其执行的速度比后者要快得多,但是如果编译完成之后有问题的话,