網路超時檢測-alarm()函式
阿新 • • 發佈:2019-02-04
alarm()函式
1、在利用alarm()函式實現網路超時檢測時,相比較於其他兩種方式的特點是:
每呼叫alarm()函式一次,函式只會執行一次,並且只對最近的一個阻塞函式有效
2、電泳alarm()後,在到達設定的時間時,系統會認定alarm()最近的一個阻塞函式為錯誤,讓其返回值小於0;
當執行alarm()時間,在這期間還會執行下面的函式,直到到達時間後,會進行訊號處理函式,之後會繼續原來的函式往下執行,將其稱之為自重啟屬性
如果想要實現超時檢測,需要跳過之後的函式往下執行。
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
功能:檢測和改變一個訊號的行為
引數:
signum:訊號,除了不能改變的訊號(SIGKILL, SIGSTOP)
act:新的訊號的屬性
oldact:老的訊號的屬性
返回值:
成功:0
失敗:-1
+++++++++++++++++++++++++++++
struct sigaction {
void (*sa_handler)(int ); //訊號處理函式
void (*sa_sigaction)(int, siginfo_t *, void *); //訊號處理函式
sigset_t sa_mask; //掩碼(關於阻塞)
int sa_flags; //標誌位(設定訊號屬性)
=====>
SA_RESTART 自重啟屬性
void (*sa_restorer)(void); //沒用
};
+++++++++++++++++++++++++++++++++++++++++++++++++++
//每呼叫alarm函式只會執行一次,並且只會對最近的一個函式有效
//位操作 讀、改、寫
//讀取原來訊號的屬性
struct sigaction act;
if(sigaction(SIGALRM, NULL, &act) < 0)
{
errlog("fail to sigaction");
}
//修改對應屬性
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART;
//act.sa_flags = act.sa_flags & (~SA_RESTART);
//將新的屬性寫入訊號
if(sigaction(SIGALRM, &act, NULL) < 0)
{
errlog("fail to sigaction");
}
alarm(5);
++++++++++++++++++++++++++++++++++++++++++++++++++++
下面上例項:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#define N 128
#define errlog(errmsg) do{perror(errmsg); exit(1);}while(0)
void handler(int sig)
{
}
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr, clientaddr;
int acceptfd;
socklen_t addrlen = sizeof(struct sockaddr_in);
char buf[N] = {};
//建立套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
errlog("fail to socket");
}
//填充網路資訊結構體
//inet_addr 將點分十進位制轉化成網路位元組
//htons表示將主機位元組序轉化成網路位元組序
//atoi 將字串轉化成整型資料
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//將套接字與IP地址和埠號繫結
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
errlog("fail to bind");
}
//將套接字設定為被動監聽狀態
if(listen(sockfd, 10) < 0)
{
errlog("fail to listen");
}
//使用alarm鬧鐘實現網路超時檢測
//每呼叫alarm函式只會執行一次,並且只會對最近的一個函式有效
//位操作 讀、改、寫
//讀取原來訊號的屬性
struct sigaction act;
if(sigaction(SIGALRM, NULL, &act) < 0)
{
errlog("fail to sigaction");
}
//修改對應屬性
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART;
//act.sa_flags = act.sa_flags & (~SA_RESTART);
//將新的屬性寫入訊號
if(sigaction(SIGALRM, &act, NULL) < 0)
{
errlog("fail to sigaction");
}
while(1)
{
alarm(5);
printf("11111\n");
//接收客戶端的連線請求
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
//printf("errno = %d\n", errno);
if(errno == 4)
{
printf("accept timeout ...\n");
}
else
{
errlog("fail to accept");
}
}
else
{
printf("%s ---> %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
//與客戶端進行通訊
while(1)
{
alarm(5);
if(recv(acceptfd, buf, N, 0) < 0)
{
if(errno == 4)
{
printf("recv timeout ...\n");
}
else
{
errlog("fail to recv");
}
}
else
{
if(strncmp(buf, "quit", 4) == 0)
{
printf("%s is quited...\n", inet_ntoa(clientaddr.sin_addr));
break;
}
else
{
printf("from client >>> %s\n", buf);
strcat(buf, " from server...");
if(send(acceptfd, buf, N, 0) < 0)
{
errlog("fail to send");
}
}
}
}
}
}
close(sockfd);
close(acceptfd);
return 0;
}