connect方法会阻塞,请问有什么方法可以避免其长时间阻塞?

在学习嵌入式Linux网络编程中,很多同学都发现了一个问题,那就是调用connect函数时,如果服务端关闭,客户 端调用connect()函数时,发现阻塞在那里,而且利用ctrl+c信号去停止客户端程序时,需要等待一个较为长的时间才能响应了,这个时间如果大家 细心会发现,每次都是75秒的时间。那么有没有什么比较好的办法,可以以用户能接受的一个时间响应来停止掉一个正在connect连接的客户端那?

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

作者:hj605635529

来源:CSDN

原文:https://blog.csdn.net/hj605635529/article/details/74157305

版权声明:本文为博主原创文章,转载请附上博文链接!




步骤1: 设置非阻塞,启动连接

实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的。这样调用

connect 可以立刻返回,根据返回值和 errno 处理三种情况:

(1) 如果返回 0,表示 connect 成功。

(2) 如果返回值小于 0, errno 为 EINPROGRESS, ?表示连接

? ? ? 建立已经启动但是尚未完成。这是期望的结果,不是真正的错误。

(3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。

?

步骤2:判断可读和可写

然后把 sockfd 加入 select 的读写监听集合,通过 select 判断 sockfd

是否可写,

(1) 如果连接建立好了,,那么 sockfd 是可写的

(2) 如果连接发生错误,sockfd 也是可读和可写的。

步骤3:使用 getsockopt 函数检查错误

getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len)

在 sockfd 都是可读和可写的情况下,我们使用 getsockopt 来检查连接

是否出错。但这里有一个可移植性的问题。

如果发生错误,getsockopt 源自 Berkeley 的实现将在变量 err 中

返回错误,getsockopt 本身返回0;(centos是这种错误)

然而 Solaris 却让 getsockopt 返回 -1,

并把错误保存在 errno 变量中。所以在判断是否有错误的时候,要处理

这两种情况。

步骤4:重新将套接字设置为阻塞

#include<stdio.h>

#include<sys/socket.h>

#include<sys/types.h>

#include<arpa/inet.h>

#include<string.h>

#include<netinet/in.h>

#include<string.h>

#include <sys/select.h>

#include<fcntl.h>

/* According to earlier standards */

#include <sys/time.h>

#include <unistd.h>

#include<errno.h>

static void usage(const char *str)

{

printf("Usage:%s,[IP],[PORT]\n",str);

}

int main(int argc ,char *argv[])

{

int sock = socket(AF_INET,SOCK_STREAM,0);

if(sock < 0)

{

perror("sock");

return 1;

}

struct sockaddr_in serv_addr;

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(atoi(argv[2]));

serv_addr.sin_addr.s_addr = inet_addr(argv[1]);

int flag,old_flag;

flag |= O_NONBLOCK;

old_flag = flag = fcntl(sock, F_SETFL, O_NONBLOCK ); //将连接套接字设置为非阻塞。

int ret = connect(sock,(struct sockaddr*)& serv_addr,sizeof(serv_addr));

if(ret != 0)

{

if(errno != EINPROGRESS) //connect返回错误。

{

printf("connect failed\n");

}

//连接正在建立

else

{

struct timeval tm;  //1.定时

tm.tv_sec = 10;

tm.tv_usec = 0;

fd_set wset;

FD_ZERO(&wset);

FD_SET(sock,&wset);

printf("selcet start\n");

int res = select(sock+1, NULL, &wset, NULL, &tm);

printf("select end\n");

if(res <= 0)

{

printf("res <= 0\n");

close(sock);

return 2;

}

if(FD_ISSET(sock,&wset))

{

printf("test \n");

int err = -1;

socklen_t len = sizeof(int);

if(getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len ) < 0) //两种错误处理方式

{

printf("errno :%d %s\n",errno, strerror(errno));

close(sock);

return 3;

}

if(err)

{

printf("connect faile\n");

errno = err;

close(sock);

return 4;

}

printf("connetct success\n");

}

}

}

fcntl(sock, F_SETFL, old_flag); //最后恢复sock的阻塞属性。

char buf[BUFSIZ];

while(1)

{

printf("client say# ");

fflush(stdout);

ssize_t s = read(0,buf,sizeof(buf) - 1);

if(s > 0)

{

buf[s - 1] = 0;

write(sock,buf,strlen(buf));

ssize_t s2 = read(sock,buf,sizeof(buf) -1 );

if(s2 > 0)

{

buf[s2] = 0;

printf("server echo # %s\n",buf);

}

}

}

return 0;

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容