在socket编程中调用connect函数连接一远程机器,假如该ip不存在的话,connect将在一段时间内返回-1表示失败。问题是有时候我们需要准确控制connect函数连接的时间,这就需要我们能够控制这个connect函数。但是,gcc给我们提供的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)

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!