当前位置:网站首页>I/O复用的高级应用之一:非阻塞 connect———使用 select 实现(也可以用 poll 实现)
I/O复用的高级应用之一:非阻塞 connect———使用 select 实现(也可以用 poll 实现)
2022-04-23 14:36:00 【m0_51551385】
一、啥是 非阻塞 connect?
我们之前唯一使用过的非阻塞socket文件描述符是在服务器中,使用非阻塞的方式可以大大提升服务器程序的效率。
现在试想,我们把客户端程序的 socket 设置为非阻塞的,那么用该 socket 文件描述符进行 connect 连接就很容易报错。为什么呢?因为,非阻塞下,对该文件描述符的调用直接返回结果,而 socket 连接很难这么快完成,所以就很容易调用失败,此时会设置errno的值为:EINPROGRESS。该错误类型发生在,对非阻塞的 socket 调用 connect,而连接又没有建立时。所以当 connect 返回-1时,并不一定发生了错误,可能连接还在进行中!
此事的解决方法是,调用select 、poll等函数监听这个连接失败的 socket 上的可写事件。当select 或 poll等函数返回后,再利用getsockopt读取错误码。如果错误码是0,表示刚刚的 connect 确实没发生错误,连接成功建立,若错误码为1,表示确实是发生了错误。
这么麻烦的用非阻塞 connect 有啥好处吗?
通过使用非阻塞connect,我们就能同时发起多个连接并一起等待。
2、非阻塞 connect 实例程序
下面是一个客户端程序,它使用一个非阻塞 socket 连接服务器。
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<time.h>
#include<sys/ioctl.h>
#define BUFFER_SIZE 1023
int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
/* 超时连接函数,参数分别为IP地址,端口号,和超时时间(毫秒)。成功返回连接状态的 socket,失败返回-1 */
int unblock_connect(const char* ip, int port, int time)
{
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, &address);
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
int fdopt = setnonblocking(sockfd);
ret = connect(sockfd, (struct sockaddr*)&address, sizeof(address));
if (ret == 0) /* 连接成功了 */
{
/* 如果连接成功,则恢复 sockfd 的属性,并立即返回之 */
printf("connect whit server immediately\n");
fcntl(sockfd, F_SETFL, fdopt);
return sockfd;
}
else if (errno != EINPROGRESS) /* 如果错误类型不是 EINPROGRESS,说明发生了其他的错误,立即返回 */
{
/* 如果连接没有立即建立,那么只有当 errno 是 EINPROGRESS 时才表示连接还在进行,否则出错返回 */
printf("unblock connect not support\n");
return -1;
}
fd_set readfds;
fd_set writefds;
struct timeval timeout;
FD_ZERO(&readfds);
FD_SET(sockfd, &writefds);
timeout.tv_sec = time;
timeout.tv_usec = 0;
ret = select(sockfd + 1, NULL, &writefds, NULL, &timeout);
if (ret <= 0)
{
/* select 超时或者出错,立即返回 */
printf("connection time out\n");
close(sockfd);
return -1;
}
if (!FD_ISSET(sockfd, &writefds)) /* 如果 sockfd 不可写,说明连接失败了,立即返回 */
{
printf("no events on sockfd found\n");
close(sockfd);
return -1;
}
int error = 0;
socklen_t length = sizeof(error);
/* 调用 getsockopt 来获取并清除 sockfd 上的错误 */
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
{
printf("connection failed after select with the error: %d\n", error);
close(sockfd);
return -1;
}
/* 错误号不为 0 表示连接出错 */
if (error != 0)
{
printf("connection failed after select with the error: %d\n", error);
close(sockfd);
return -1;
}
/* 连接成功 */
printf("connection ready after select with the socket: %d\n", sockfd);
fcntl(sockfd, F_SETFL, fdopt);
return sockfd;
}
int main(int argc, char* argv[])
{
if (argc <= 2)
{
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int sockfd = unblock_connect(ip, port, 10);
if (sockfd < 0)
{
return 1;
}
close(sockfd);
return 0;
}
版权声明
本文为[m0_51551385]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_51551385/article/details/124362567
边栏推荐
- Qt界面优化:Qt去边框与窗体圆角化
- 在游戏世界组建一支AI团队,超参数的多智能体「大乱斗」开赛
- Matrix exchange row and column
- Sed learning for application
- kprobe 的 3 种使用
- Electronic perpetual calendar of DS1302_ 51 single chip microcomputer, month, day, week, hour, minute and second, lunar calendar and temperature, with alarm clock and complete set of data
- source insight via samba
- Matlab Simulink modeling and design of single-phase AC-AC frequency converter, with MATLAB simulation, PPT and papers
- Parameter stack pressing problem of C language in structure parameter transmission
- 交通灯系统51单片机设计(附Proteus仿真、C程序、原理图及PCB、论文等全套资料)
猜你喜欢

Proteus simulation design of four storey and eight storey elevator control system, 51 single chip microcomputer, with simulation and keil c code

A good tool: aardio

A blog allows you to learn how to write markdown on vscode

AT89C52 MCU frequency meter (1Hz ~ 20MHz) design, LCD1602 display, including simulation, schematic diagram, PCB and code, etc

【Servlet】Servlet 详解(使用+原理)

一款不错的工具:aardio

PCIe X1 插槽的主要用途是什么?

SVN详细使用教程

Electronic perpetual calendar of DS1302_ 51 single chip microcomputer, month, day, week, hour, minute and second, lunar calendar and temperature, with alarm clock and complete set of data

抑郁症治疗的进展
随机推荐
51 MCU flowers, farmland automatic irrigation system development, proteus simulation, schematic diagram and C code
Redis源码分析之HSET流程与ziplist
8.5 循环神经网络简洁实现
raised exception class EAccexxViolation with ‘Access violation at address 45EFD5 in module 出错
机器学习之逻辑回归(Logistic Regression)原理讲解和实例应用,果断收藏
关于UDP接收icmp端口不可达(port unreachable)
flannel 原理 之 TUN模式
外包干了四年,废了...
AT89C51单片机的数字电压表开发,量程0~5V,proteus仿真,原理图PCB和C程序等
51单片机的直流电机PWM调速控制系统(附Proteus仿真+C程序等全套资料)
Design of single chip microcomputer Proteus for temperature and humidity monitoring and alarm system of SHT11 sensor (with simulation + paper + program, etc.)
【无标题】
Solve the problem of SSH configuration file optimization and slow connection
浅谈skiplist在LevelDB的应用
A blog allows you to learn how to write markdown on vscode
On the insecurity of using scanf in VS
51 Single Chip Microcomputer Design of traffic light system (with Proteus simulation, C program, schematic diagram, PCB, thesis and other complete data)
ArrayList collection basic usage
Electronic scale weighing system design, hx711 pressure sensor, 51 single chip microcomputer (proteus simulation, C program, schematic diagram, thesis and other complete data)
Proteus simulation design of four storey and eight storey elevator control system, 51 single chip microcomputer, with simulation and keil c code