1. 程式人生 > >網路超時檢測-alarm()函式

網路超時檢測-alarm()函式

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;
}