歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> 關於Unix

創建能夠超時的socket連結API

在socket編程中調用connect函數連接一遠程機器,如果該ip不存在的話,connect將在一段時間內返回-1表示失敗。問題是有時候我們需要准確控制connect函數連接的時間,這就需要我們能夠控制這個connect函數。但是,gcc給我們提供的API沒有這個功能。我自己設計了 在socket編程中調用connect函數連接一遠程機器,如果該ip不存在的話,connect將在一段時間內返回-1表示失敗。問題是有時候我們需要准確控制connect函數連接的時間,這就需要我們能夠控制這個connect函數。但是,gclearcase/" target="_blank" >cc給我們提供的API沒有這個功能。我自己設計了一個這樣的API函數--connect2,它能夠在用戶設置的一段時間後,連接超時退出。

      這個connect2的初步設計思想是利用多線程,創建一個獨立的線程調用socket的connect函數去連接,這樣這個線程就可以被殺掉。我們首先要根據用戶的需求設立一個alarm,並設置好alarm到點之後的動作,那就是取消掉連接線程。如果在alarm到點之前這個線程已經返回那就返回連接成功,否則連接線程將被取消,也就說明連接在規定的時間內失敗,函數返回失敗。

      好了。設計思想比較簡單。下面來看看實現。
//函數定義

int connect2(SOCKET sock,struct sockaddr * addr,int timeout)

//函數實現

/**This implementation is for LINUX
* @version 1.0
* @author Jerry Hou
*/
#include
#include
#include
#include
#include
#include
#include "connect_timeout.h"
int g_sock;
pthread_t connect_thread;
void *sock_connect(void * argv);
void sock_cancel(int no);
int connect2(SOCKET sock,struct sockaddr * addr,int timeout)
{
        int res;
        struct sigaction act;
        g_sock=sock;
        res=pthread_create(&connect_thread,NULL,sock_connect,(void *)addr);
        if(res!=0)
                return errno;
        act.sa_handler=sock_cancel;
        sigemptyset(&act.sa_mask);
        act.sa_flags=0;
        if(sigaction(SIGALRM,&act,NULL)<0)
        {
                return errno;
        }

        alarm(timeout);
        int * pres=NULL;
        res=pthread_join(connect_thread,(void **)&pres);
        alarm(0);
        if(res!=0)
                return errno;
        if(pres!=NULL)
        if(pres==PTHREAD_CANCELED)
                return -1;
        return *pres;
  

}
void * sock_connect(void * argv)
{
        struct sockaddr * s_addr=(struct sockaddr *)argv;
        int *pres=(int *)malloc(sizeof(int));
        int res=connect(g_sock,s_addr,sizeof(struct sockaddr_in));
        *pres=res;
        pthread_exit(pres);
}
void sock_cancel(int no)
{
        pthread_cancel(connect_thread);
//      timeout=1;
}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

這個connect2 API能夠較准確在規定時間內TIMEOUT,但是還有一些問題。先不說了,改天有空再說。希望有人捧場。

     接著上面的討論。細心的朋友會發現這個connect2函數的問題,那就是它只能允許在一個connect2調用完才能進行第二個調用,否則另外一個調用會影響到前面的調用。也就是說,只能在單線程中使用,不是線程安全(thread-safe)或可重入的(reentrant)。
     造成這個原因一是設計中我們調用了alarm這個gcc庫的api,而它是進程范圍的,也就是說後邊alarm設置會影響到前面的設置。二是我們使用了2個全局變量,這樣後邊的connect2調用會改寫這2個變量影響到前面的調用。
     解決的辦法是我們需要一個線程安全的定時器timer,無論哪個定時器的設置都不會影響到其他的定時器工作。理想的這樣一個timer函數應該是這樣定義的:
int timer(int seconds,(void)ontimer(void * agrv) ,void *argv); 其中,seconds是超時時間,timerfunc是超時要執行的函數地址,argv是傳入該函數的參數。好,我們假設有了這樣一個線程安全的timer,我們來重寫connect2。timer的實現我放在另外一篇文章裡單獨介紹,因為它不僅可以用在這裡。

/**This implementation is for LINUX
* @version 1.1
* @author Jerry Hou
*/
#include
#include
#include
#include
#include
#include "timer.h"  //header file containing definitions of timer related APIs
#include "connect_timeout.h"

void * sock_connect(void * argv);
void  sock_cancel(void * argv);
int connect2(SOCKET sock,struct sockaddr * addr,int timeout)
{
        int res;
        pthread_t connect_thread;
        res=pthread_create(&connect_thread,NULL,sock_connect,(void *)addr);
        if(res!=0)
                return errno;
        res=timer(timeout,socke_cancel,(void *)&connect_thread);
        if(res!=0)
                return res;
        int * pres=NULL;
        res=pthread_join(connect_thread,(void **)&pres);
        if(res!=0)
                return errno;
        if(pres!=NULL)
        if(pres==PTHREAD_CANCELED)
                return -1;
        return *pres;
  

}
void * sock_connect(void * argv)
{
        struct sockaddr * s_addr=(struct sockaddr *)argv;
        int *pres=(int *)malloc(sizeof(int));
        int res=connect(g_sock,s_addr,sizeof(struct sockaddr_in));
        *pres=res;
        pthread_exit(pres);
}
void  sock_cancel(void * argv)
{
        pthead_t *pthread=(pthead_t *)argv;
        pthread_cancel(pthread);
//      timeout=1;
}

Copyright © Linux教程網 All Rights Reserved