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

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


  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值