当前位置: 首页 > news >正文

connect的非阻塞模式

本文参考:connect 函数在阻塞和非阻塞模式下的行为

一般情况下,在使用connect连接服务端时,需要等待一会儿才会函数才会返回,导致程序阻塞。为了降低阻塞的影响,我们可能会单独开个线程处理connect请求,例如在界面当中,就会启用一个线程,避免UI卡死。
当然,这里还有一些其他的方法,也就是我们常见的非阻塞IO。

主要步骤大致如下:

  1. 创建socket,并将 socket 设置成非阻塞模式;
  2. 调用 connect 函数,此时无论 connect 函数是否连接成功会立即返回;如果返回-1并不表示连接出错,如果此时错误码是EINPROGRESS
  3. 接着调用 select 函数,在指定的时间内判断该 socket 是否可写,如果可写说明连接成功,反之则认为连接失败。

按上述流程编写代码如下:

  /*** Linux 下正确的异步的connect写法,linux_nonblocking_connect.cpp* zhangyl 2018.12.17*/#include <sys/types.h> #include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <iostream>#include <string.h>#include <stdio.h>#include <fcntl.h>#include <errno.h>#define SERVER_ADDRESS "127.0.0.1"#define SERVER_PORT     3000#define SEND_DATA       "helloworld"int main(int argc, char* argv[]){//1.创建一个socketint clientfd = socket(AF_INET, SOCK_STREAM, 0);if (clientfd == -1){std::cout << "create client socket error." << std::endl;return -1;}//连接成功以后,我们再将 clientfd 设置成非阻塞模式,//不能在创建时就设置,这样会影响到 connect 函数的行为int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);int newSocketFlag = oldSocketFlag | O_NONBLOCK;if (fcntl(clientfd, F_SETFL,  newSocketFlag) == -1){close(clientfd);std::cout << "set socket to nonblock error." << std::endl;return -1;}//2.连接服务器struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);serveraddr.sin_port = htons(SERVER_PORT);for (;;){int ret = connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if (ret == 0){std::cout << "connect to server successfully." << std::endl;close(clientfd);return 0;} else if (ret == -1) {if (errno == EINTR){//connect 动作被信号中断,重试connectstd::cout << "connecting interruptted by signal, try again." << std::endl;continue;} else if (errno == EINPROGRESS){//连接正在尝试中break;} else {//真的出错了,close(clientfd);return -1;}}}fd_set writeset;FD_ZERO(&writeset);FD_SET(clientfd, &writeset);//可以利用tv_sec和tv_usec做更小精度的超时控制struct timeval tv;tv.tv_sec = 3;  tv.tv_usec = 0;if (select(clientfd + 1, NULL, &writeset, NULL, &tv) != 1){std::cout << "[select] connect to server error." << std::endl;close(clientfd);return -1;}int err;socklen_t len = static_cast<socklen_t>(sizeof err);if (::getsockopt(clientfd, SOL_SOCKET, SO_ERROR, &err, &len) < 0){close(clientfd);return -1;}if (err == 0)std::cout << "connect to server successfully." << std::endl;elsestd::cout << "connect to server error." << std::endl;//5. 关闭socketclose(clientfd);return 0;}
http://www.lryc.cn/news/407795.html

相关文章:

  • jenkins面试题全集
  • Python中最好学和最实用的有哪些库和框架
  • 文件解析的终极工具:Apache Tika
  • Hadoop 重要监控指标
  • oracle 查询锁表
  • 进程概念(三)----- fork 初识
  • huawei 路由 RIP 协议中三种定时器的工作原理
  • HTML常见标签——超链接a标签
  • Python 爬虫入门(一):从零开始学爬虫 「详细介绍」
  • Linux嵌入式学习——数据结构——概念和Seqlist
  • iOS ------ Block的相关问题
  • conda issue
  • 为了解决地图引入鉴权失败的解决方案
  • [ptrade交易实战] 第十八篇 期货查询类函数和期货设置类函数
  • STM32智能家居控制系统教程
  • FPGA 中的 IOE与IO BANK
  • ADetailer模型+Stable Diffusion的inpainting功能是如何对遮罩区域进行修复生成的ADetailer
  • 【博士每天一篇文献-综述】2024机器遗忘最新综述之一:An overview of machine unlearning
  • 【机器学习】Jupyter Notebook如何使用之基本步骤和进阶操作
  • C++ | Leetcode C++题解之第279题完全平方数
  • Vue 3 响应式高阶用法之 `shallowRef()` 详解
  • 流量录制与回放:jvm-sandbox-repeater工具详解
  • 内网渗透—内网穿透工具NgrokFRPNPSSPP
  • 嵌入式中传感器数据处理方法
  • 生成式 AI 的发展方向,是 Chat 还是 Agent?
  • 金字塔监督在人脸反欺骗中的应用
  • vue3——两种利用自定义指令实现防止按钮重复点击的方法
  • Chrome谷歌浏览器Console(控制台)显示文件名及行数
  • Vue3+Element Plus 实现table表格中input的验证
  • 安宝特方案|解放双手,解决死角,AR带来质量监督新体验