signal.c:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void timeout(int sig){
if(sig == SIGALRM){
puts("Time out!");
}
alarm(2);
}
void keycontrol(int sig){
if(sig == SIGINT){
puts("CTRL+C pressed");
}
}
int main(){
int i;
signal(SIGALRM,timeout);
signal(SIGINT,keycontrol);
alarm(2);
for(i=0;i<3;++i){
puts("wait...");
sleep(100);
}
return 0;
}
运行结果:
[root@VM_0_10_centos Signal] gcc signal.c -o signal
[root@VM_0_10_centos Signal] ./signal
wait...
Time out!
wait...
Time out!
wait...
Time out!
[root@VM_0_10_centos Signal]# ./signal
wait...
Time out!
wait...
Time out!
wait...
^CCTRL+C pressed
[root@VM_0_10_centos Signal]#
发生信号时将唤醒由于调用sleep函数而进入阻塞状态的进程。
sigaction.c更常用:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void timeout(int sig){
if(sig == SIGALRM){
puts("Time out!");
}
alarm(2);
}
int main(int argc,char * argv[]){
int i;
struct sigaction act;
act.sa_handler = timeout;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM,&act,0);
alarm(2);
for(i=0;i<3;++i){
puts("wait...");
sleep(100);
}
return 0;
}
运行结果:
[root@VM_0_10_centos Signal] gcc sigaction.c
[root@VM_0_10_centos Signal] gcc sigaction.c -o sigaction
[root@VM_0_10_centos Signal] ./sigaction
wait...
Time out!
wait...
Time out!
wait...
Time out!
[root@VM_0_10_centos Signal]#
由于子进程终止时会产生SIGCHLD
信号,这样就可以用信号处理技术消灭僵尸进程:
remove_zombie.c:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
void read_childproc(int sig){
int status;
pid_t id = waitpid(-1,&status,WNOHANG);
if(WIFEXITED(status)){
printf("Removed proc id: %d \n",id);
printf("Child send: %d \n",WEXITSTATUS(status));
}
}
int main(int argc, char* argv[]){
pid_t pid;
struct sigaction act;
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD,&act,0);
pid = fork();
if(pid == 0){
puts("This is child process1");
sleep(10);
return 12;
}else{
printf("Child Pid is: %d \n",pid);
pid = fork();
if(pid == 0){
puts("This is child process2");
sleep(10);
exit(25);
}else{
int i=0;
printf("Child Pid is: %d \n",pid);
for(i=0;i<5;++i){
puts("wait...");
sleep(5);
}
}
}
return 0;
}
运行结果:
[root@VM_0_10_centos Signal]# gcc remove_zombie.c -o zombie
[root@VM_0_10_centos Signal]# ./zombie
Child Pid is: 21533
Child Pid is: 21534
wait...
This is child process2
This is child process1
wait...
Removed proc id: 21534
Child send: 25
wait...
Removed proc id: 21533
Child send: 12
wait...
wait...
并发服务器:
echo_mpserver.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 30
void error_handling(char * message);
void read_childproc(int sig);
int main(int argc,char* argv[]){
int serv_sock,clnt_sock;
struct sockaddr_in serv_adr,clnt_adr;
pid_t pid;
struct sigaction act;
socklen_t adr_sz;
int str_len,state;
char buf[BUF_SIZE];
if(argc != 2){
printf("Usage:%s <port> \n",argv[0]);
exit(1);
}
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
state = sigaction(SIGCHLD, &act, 0);
serv_sock = socket(PF_INET,SOCK_STREAM,0);
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock,(struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1){
error_handling("bind() error");
}
if(listen(serv_sock,5)==-1){
error_handling("listen() error");
}
while(1){
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
if(clnt_sock == -1){
continue;
}else{
puts("new client connected...");
}
pid = fork();
if(pid == -1){
close(clnt_sock);
continue;
}
if(pid == 0){
close(serv_sock);
while((str_len = read(clnt_sock,buf,BUF_SIZE)) != 0){
write(clnt_sock, buf, str_len);
}
close(clnt_sock);
puts("client disconnected...");
return 0;
}else{
close(clnt_sock);
}
}
close(serv_sock);
return 0;
}
void read_childproc(int sig){
pid_t pid;
int status;
pid = waitpid(-1,&status,WNOHANG);
printf("remove proc id: %d \n",pid);
}
void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
echo_client.c :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char * message);
int main(int argc, char* argv[]){
int sock;
char message[BUF_SIZE];
int str_len;
struct sockaddr_in serv_adr;
if(argc != 3){
printf("Usage:%s <port> \n",argv[0]);
exit(1);
}
sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock == -1){
error_handling("socket() error");
}
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
if(connect(sock,(struct sockaddr*)& serv_adr, sizeof(serv_adr)) == -1){
error_handling("connect() error");
}else{
puts("Connected.....");
}
while(1){
fputs("Input message(Q to quit):",stdout);
fgets(message, BUF_SIZE, stdin);
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n")){
break;
}
write(sock, message, strlen(message));
str_len = read(sock, message, BUF_SIZE-1);
message[str_len] = 0;
printf("Message from server:%s",message);
}
close(sock);
return 0;
}
void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
运行结果:
分割I/O的回声客户端:
echo_mpclient.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 30
void error_handling(char * message);
void read_routine(int sock,char *buf);
void write_routine(int sock,char *buf);
int main(int argc, char * argv[]){
int sock;
pid_t pid;
char buf[BUF_SIZE];
struct sockaddr_in serv_adr;
if(argc != 3){
printf("Usage:%s <IP> <PORT>");
exit(1);
}
sock = socket(PF_INET,SOCK_STREAM,0);
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){
error_handling("connect() error");
}
pid = fork();
if(pid == 0){
write_routine(sock,buf);
}else{
read_routine(sock,buf);
}
close(sock);
return 0;
}
void read_routine(int sock, char* buf){
while(1){
int str_len = read(sock,buf,BUF_SIZE);
if(str_len == 0){
return;
}
buf[str_len] = 0;
printf("Message from server:%s",buf);
}
}
void write_routine(int sock,char * buf){
while(1){
fgets(buf,BUF_SIZE,stdin);
if(!strcmp(buf,"q\n") || !strcmp(buf,"Q\n")){
shutdown(sock,SHUT_WR);
return;
}
write(sock,buf,strlen(buf));
}
}
void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
运行结果:
课后题3:
创建子进程时将复制父进程的所有内容,此时的复制对象也包含套接字文件描述符。编写程序验证复制的文件描述符整数值是否与原文件描述符整数值相同。
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
int main(){
pid_t pid;
int sockfd = socket(PF_INET,SOCK_STREAM,0);
pid = fork();
if(pid == 0){
printf("sockfd = %d\n",sockfd);
}else{
printf("sockfd = %d\n",sockfd);
}
return 0;
}
课后题4:
请说明进程变为僵尸进程的过程及预防措施
僵尸进程是子进程。在子进程结束时,其返回值会传到操作系统,直到返回值被其父进程接收为止,该(子)进程会一直作为僵尸进程存在。所以,为了防止这种情况的发生,父进程必须明确接收子进程结束时的返回值。
课后题5:
编写程序使其每隔1秒输出简单字符串,并适用于上述时间处理器注册代码
注意:puts(“会直接打印到stdout,后面无需添加\n或者,stdout”);而fputs(“需要打印的字符串,stdout”);
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void ctrl_handler(int sig);
int main(){
struct sigaction act;
act.sa_handler = ctrl_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT,&act,0);
while(1){
sleep(1);
puts("good luck!");
}
return 0;
}
void ctrl_handler(int sig){
char in;
fputs("Do you want to exit?",stdout);
scanf("%c",&in);
if(in == 'y' || in == 'Y'){
exit(1);
}
}
运行结果:
[root@VM_0_10_centos Signal]# ./test5
good luck!
good luck!
good luck!
good luck!
^CDo you want to exit?y
[root@VM_0_10_centos Signal]#