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