歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux-信號處理

Linux-信號處理

日期:2017/3/1 10:18:42   编辑:Linux編程
信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一個中斷請求可以說是一樣的。信號是異步的,一個進程不必通過任何操作來等待信號的到達,事實上,進程也不知道信號到底什麼時候到達。

信號是進程間通信機制中唯一的異步通信機制,可以看作是異步通知,通知接收信號的進程有哪些事情發生了。

每個信號都有一個名字,以SIG打頭。常見的SIGINT( 終端終止符)、SIGABRT(異常終止,abort()產生)、SIGUSR1(用戶定義的信號)等。

當信號產生,有三種方式處理該信號

  1. 忽略信號,兩種信號(SIGKILL,SIGSTOP不能忽略)
  2. 捕捉信號,用戶可以自己定義函數用於處理該信號。
  3. 執行系統默認動作,一般默認動作是終止進程
在某些情況下,我們需要捕捉信號。比如說,之前編寫的echo服務器,服務端按ctrl+c產生SIGINT信號,終止服務端程序。但是某些時候,我需要在終止程序前,做一些善後工作,如釋放申請的內存空間,以免造成內存洩露。所以信號捕捉是有用的。

可以使用signal為信號指定信號處理函數,也可以使用sigaction。現在推薦使用sigaction。

  1. #include <signal.h> //信號頭文件
  2. typedef void (*__sighandler_t) (int);
  3. __sighandler_t signal (int __sig, __sighandler_t __handler);
signal有兩個參數,一個是信號量,另一個是函數指針。

下面以echo服務器,來說明如何自定義信號處理函數。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/socket.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <signal.h> //信號頭文件
  9. #define SERVERIP "192.168.0.23"
  10. #define SERVERPORT 12345
  11. #define MAXBUFFER 256
  12. int serverFd=-1, connfd=-1;
  13. char *readBuf=NULL;
  14. /*
  15. *功能:SIGINT自定義處理函數,用於釋放申請的內存空間
  16. */
  17. void handInt(int signo)
  18. {
  19. printf("捕捉到SIGINT信號,服務端被終止,善後處理中...\n");
  20. if (readBuf != NULL)
  21. {
  22. free(readBuf);
  23. readBuf = NULL;
  24. }
  25. close(serverFd);
  26. close(connfd);
  27. exit(-1);
  28. }
  29. int main(int argc, char** argv)
  30. {
  31. int ret;
  32. readBuf=(char *)malloc(MAXBUFFER);
  33. socklen_t len;
  34. struct sockaddr_in serveraddr,clientaddr;
  35. char ip[40]={0};
  36. serverFd=socket(AF_INET,SOCK_STREAM,0);//創建socket
  37. if(serverFd < 0)
  38. {
  39. printf("socket error:%s\n",strerror(errno));
  40. exit(-1);
  41. }
  42. bzero(&serveraddr,sizeof(serveraddr));
  43. serveraddr.sin_family=AF_INET;
  44. serveraddr.sin_port=htons(SERVERPORT);
  45. inet_pton(AF_INET,SERVERIP,&serveraddr.sin_addr);//將c語言字節序轉換為網絡字節序
  46. if (signal(SIGINT, handInt) == SIG_ERR)//注冊信號處理函數
  47. {
  48. printf("signal error: %s", strerror(errno));
  49. free(readBuf);
  50. exit(-1);
  51. }
  52. ret=bind(serverFd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));//綁定IP和端口
  53. if(ret!=0)
  54. {
  55. close(serverFd);
  56. printf("bind error:%s\n",strerror(errno));
  57. exit(-1);
  58. }
  59. ret=listen(serverFd,5);//監聽
  60. if(ret!=0)
  61. {
  62. close(serverFd);
  63. printf("listen error:%s\n",strerror(errno));
  64. exit(-1);
  65. }
  66. len=sizeof(clientaddr);
  67. bzero(&clientaddr,sizeof(clientaddr));
  68. while (1)
  69. {
  70. connfd = accept(serverFd, (struct sockaddr *) &clientaddr, &len);//接受客戶端的連接
  71. printf("%s 連接到服務器 \n",inet_ntop(AF_INET,&clientaddr.sin_addr,ip,sizeof(ip)));
  72. if (serverFd < 0)
  73. {
  74. printf("accept error : %s\n", strerror(errno));
  75. continue;
  76. }
  77. while((ret=read(connfd,readBuf,MAXBUFFER)))//讀客戶端發送的數據
  78. {
  79. write(connfd,readBuf,MAXBUFFER);//寫回客戶端
  80. bzero(readBuf,MAXBUFFER);
  81. }
  82. if(ret==0)
  83. {
  84. printf("客戶端關閉連接\n");
  85. }else
  86. {
  87. printf("read error:%s\n",strerror(errno));
  88. }
  89. close(connfd);
  90. }
  91. free(readBuf);
  92. close(serverFd);
  93. return 0;
  94. }
當沒有捕捉SIGINT信號時,采用默認處理方式,終止程序。但是程序中用alloc分配了內存,程序終止前並沒有釋放。用valgrind 檢測會出現內存洩露


如圖所示,分配了一個內存空間,釋放了0個內存空間。

但為SIGINT加上信號處理函數,在終止前,釋放掉內存空間,就不會出現內存洩露了。效果如下所示:

Copyright © Linux教程網 All Rights Reserved