15.信号通信编程
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进程进行了自行出理。这样我们就可以实现进程间的通信机制了。