1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > TCP Connect 函数超时的问题

TCP Connect 函数超时的问题

时间:2019-03-29 09:05:18

相关推荐

TCP Connect 函数超时的问题

TCP 客户端通过 connect 函数连接服务器时,若服务器此时不在线或者当前网络不正常,会在 connect 函数中阻塞(默认情况下系统使用阻塞式 socket),直到超时时间到达,而这个超时时间是由内核规定的,这会导致连接时间较长,此时若是客户端还需要完成其他活动,则会影响正常业务。

此时,我们可以通过将链路设置成非阻塞模式,并通过 select 函数设置超时时长,在超时时间内轮询套接字状态,若状态可写则进一步通过 getsocket 函数确认是否连接上服务器(因为可写状态不仅是连接上服务器这1种情况,其他情况也有可能出现)。

具体步骤如下:

step1,把 socket 设置成非阻塞;step2,通过 connect 函数连接服务器,在非阻塞模式下会立刻返回,0代表连接成功,-1代表连接失败;step3,当 connect 不能立刻建立连接时,errno 会被置为 EINPROGRESS,表示连接正在建立的过程中,此时通过 select 函数去轮询套接字;step4,判断 select 返回值。若小于0,说明 connect 的进程出现了错误;等于0,说明 connect 超时;其他值则代表套接字可写;step5,通过 getsockopt 函数确认是否连接上服务器。若无错误则代表连接上,返回错误代表未连接上;step6,若程序需要,把套接口设置回阻塞状态。

代码如下:

static int connect_server(char *ip, int port){int sockfd = -1;struct sockaddr_in servaddr;int flags = 0;if ((sockfd = socket(AF_INET, SOCK_STREAM , 0)) < 0){printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);return sockfd;}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(port);if (inet_pton(AF_INET, ip, &servaddr.sin_addr) <= 0){printf("inet_pton error for %s\n", ip);close(sockfd);sockfd = -1;return sockfd;}//把链路设置为非阻塞flags = fcntl(sockfd, F_GETFL, 0);fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){if (errno != EINPROGRESS) /* EINPROGRESS 表示连接正在建立的过程中 */{printf("connect error: %s(errno: %d)\n", strerror(errno), errno);close(sockfd);sockfd = -1;}else{int ret;fd_set write_fds;struct timeval timeout;timeout.tv_sec = 0;timeout.tv_usec = 100 * 1000; /* 连接超时时长:100ms */FD_ZERO(&write_fds);FD_SET(sockfd, &write_fds);ret = select(sockfd + 1, NULL, &write_fds, NULL, &timeout);switch (ret){case -1: /* select错误 */{printf("connect error: %s(errno: %d)\n", strerror(errno), errno);close(sockfd);sockfd = -1;break;}case 0: /* 超时 */{printf("select timeout...\n");close(sockfd);sockfd = -1;break;}default:{int error = -1;socklen_t optLen = sizeof(socklen_t);getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &optLen); /* 通过 getsockopt 替代 FD_ISSET 判断是否连接 */if (error != 0){printf("connect error: %s(errno: %d)\n", strerror(errno), errno);close(sockfd);sockfd = -1;}break;}}}}return sockfd;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。