Unix上有定義了許多信號。源自Berkeley的實現使用的是SIGIO信號來支持套接字和終端設備上的信號驅動IO。
信號驅動IO模型主要是在UDP套接字上使用,在TCP套接字上幾乎是沒有什么使用的。
在UDP上,SIGIO信號會在下面兩個事件的時候產生:
1 數據報到達套接字
2 套接字上發上一部錯誤
因此我們很容易判斷SIGIO出現的時候,如果不是發生錯誤,那么就是有數據報到達了。
而在TCP上,由於TCP是雙工的,它的信號產生過於平凡,並且信號的出現幾乎沒有告訴我們發生了什么事情。因此對於TCP套接字,SIGIO信號是沒有什么使用的。
sigaction(查詢或設置信號處理方式)
int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
參數含義:
signum:所注冊的信號,我們這邊都設置為SIGIO
act :信號觸發所處理的函數
oldact:一般設置為NULL
這里涉及到了
sigaction結構
struct sigaction { void (*sa_handler) (int); sigset_t sa_mask; int sa_flags; void (*sa_restorer) (void); }
sa_handler代表的是新的信號處理函數
sa_mask 用來設置在處理該信號時暫時將sa_mask 指定的信號擱置
sa_flags 用來設置信號處理的其他相關操作
下面的例子是基於UDP的程序
服務器端:
#include <stdio.h>#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <fcntl.h> int listenfd1; void do_sigio(int sig) { int clifd, clilen; struct sockaddr_in cli_addr; char buffer[256]; clifd = accept(listenfd1, (struct sockaddr *) &cli_addr, &clilen); bzero(buffer, 256); read(clifd, buffer, 255); printf("Listenfd1 Message%s\r\n", buffer); } int main(int argc, char *argv[]) { //綁定監聽7779端口的fd struct sockaddr_in serv_addr1; listenfd1 = socket(AF_INET, SOCK_DGRAM, 0); bzero((char *) &serv_addr1, sizeof(serv_addr1)); serv_addr1.sin_family = AF_INET; serv_addr1.sin_port = htons(7779); serv_addr1.sin_addr.s_addr = INADDR_ANY; struct sigaction sigio_action; memset(&sigio_action, 0, sizeof(sigio_action)); sigio_action.sa_flags = 0; sigio_action.sa_handler = do_sigio; sigaction(SIGIO, &sigio_action, NULL); fcntl(listenfd1, F_SETOWN, getpid()); int flags; flags = fcntl(listenfd1, F_GETFL, 0); flags |= O_ASYNC | O_NONBLOCK; fcntl(listenfd1, F_SETFL, flags); bind(listenfd1, (struct sockaddr *) &serv_addr1, sizeof(serv_addr1)); while(1); close(listenfd1); return 0; }
客戶端:
#include <stdio.h>#include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <string.h> #include <unistd.h> int main(int argc, char* argv[]) { int socketfd, n; socketfd = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in serv_addr; bzero((char *)&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(7779); connect(socketfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)); write(socketfd, "client message", 14); return 0; }
運行結果: