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

posted @ 2016-02-14 08:36  cestlavie  阅读(385)  评论(0编辑  收藏  举报