connect函数在阻塞和非阻塞模式下的行为

socket使用阻塞模式时,connect函数会阻塞到有明确结果才会返回,如果网络环境较差,可能要等一会,影响体验,

为了解决这个问题,我们使用异步connect技术

  1. 创建socket,将socket设置为非阻塞模式

  2. 调用connect函数,此时无论connect函数是否连接成功,都会立即返回,如果返回-1,不一定表示连接出错,如果此时错误码为EINPROGRESS表示正在尝试连接

  3. 调用select函数,在指定时间内判断该socket是否可写,可写说明连接成功,反之,连接失败

    上述流程代码

    #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设置成非阻塞模式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);struct timeval tv;tv.tv_sec = 3;  tv.tv_usec = 0;//3.调用select函数判断socket是否可写if (select(clientfd + 1, NULL, &writeset, NULL, &tv) == 1){std::cout << "[select] connect to server successfully." << std::endl;} else {std::cout << "[select] connect to server error." << std::endl;}close(clientfd);return 0;
    }
    

    首先先用nc命令启动一个服务端程序并执行

    nc -v -l -n 0.0.0.0 3000
    

    然后运行程序,我用的clion

    把服务端关掉,在重新启动客户端,一看结果,还是

    为什么连接不上也会输出同样的结果?原因如下:

    • 在Windows上,一个socket没有建立连接之前,我们用select检测是否可写,是可以得到正确结果的,即不可写;连接成功后在检测,就会变为可写

    • 在Linux上一个socket没有建立连接之前,用select函数检测是否可写,我们也会得到可写的结果,**所以,在Linux上,我们不仅要用select检测socket是否可写还要用getsocketopt检测socket此时是否出错

      #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设置成非阻塞模式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);struct timeval tv;tv.tv_sec = 3;tv.tv_usec = 0;//3.调用select函数判断socket是否可写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);//4.调用getsockopt检测此时socket是否出错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;close(clientfd);return 0;
      }
      

TCP网络编程的基本流程

Linux与C++11多线程编程(学习笔记)

Linux select函数用法和原理

socket的阻塞模式和非阻塞模式(send和recv函数在阻塞和非阻塞模式下的表现)

connect函数在阻塞和非阻塞模式下的行为

获取socket对应的接收缓冲区中的可读数据量

connect函数在阻塞和非阻塞模式下的行为相关推荐

  1. socket的阻塞模式和非阻塞模式(send和recv函数在阻塞和非阻塞模式下的表现)

    socket的阻塞模式和非阻塞模式 无论是Windows还是Linux,默认创建socket都是阻塞模式的 在Linux中,可以再创建socket是直接将它设置为非阻塞模式 int socket (i ...

  2. Linux下connect函数 阻塞 与 非阻塞 问题

    一.概述 linux系统下,connect函数是阻塞的,阻塞时间的长度与系统相关.而如果把套接字设置成非阻塞,调用connect函数时会报错Operation now in progress,且err ...

  3. C++网络编程快速入门(三):阻塞与非阻塞式调用网络通信函数

    目录 阻塞与非阻塞定义 send与recv connect 一些问题 为什么要将监听socket设置为非阻塞 阻塞与非阻塞定义 阻塞模式指的是当前某个函数执行效果未达预期,该函数会阻塞当前的执行线程, ...

  4. socket阻塞和非阻塞模式

    socket阻塞和非阻塞模式 本文讨论Linux下的socket套接字 一.同步.异步阻塞和非阻塞 同步:主动请求并等待IO操作完成的方式 异步:主动请求数据后,可以去处理其它任务,随后等待IO操作完 ...

  5. socket connect阻塞和非阻塞处理

    建立socket后默认connect()函数为阻塞连接状态,在大多数实现中,connect的超时时间在75s至几分钟之间,想要缩短超时时间,可解决问题的两种方法:方法一.将socket句柄设置为非阻塞 ...

  6. IO模式设置,阻塞与非阻塞的比较,recv参数对性能的影响—O_NONBLOCK(open使用)、IPC_NOWAIT(msgrcv)、MSG_DONTWAIT

    非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:        基本概念: 阻塞IO:: socket 的阻塞模 ...

  7. linux非阻塞输入函数,Linux fcntl函数设置阻塞与非阻塞

    转自http://www.cnblogs.com/xuyh/p/3273082.html 用命令F_GETFL和F_SETFL设置文件标志,比如阻塞与非阻塞 F_SETFL     设置给arg描述符 ...

  8. java socket 异步回调函数_浅谈socket同步和异步、阻塞和非阻塞、I/O模型

    原标题:浅谈socket同步和异步.阻塞和非阻塞.I/O模型 在进行网络编程时,常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式 同步/异步主要针 ...

  9. select函数的阻塞和非阻塞态理解(实践总结)

    1.select函数的阻塞和非阻塞 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct tim ...

最新文章

  1. pprof搭配ceph tell命令分析ceph内存
  2. python基础语法有哪些-Python基础语法知识有哪些?
  3. boost::fibers::buffered_channel的测试程序
  4. spring cloud 微服务调用--ribbon和feign调用
  5. (24)Vue.js组件—组件注册
  6. 什么叫显示动力学_什么叫显示动力学,什么叫隐式动力学分析!
  7. Highcharts 宽度溢出容器
  8. 华南理工计算机研究生专业课,华南理工大学(专业学位)计算机技术研究生考试科目和考研参考书目...
  9. 了解HTML CSS格式化排版 文字排版
  10. 区块链实战超级账本视频教程|区块链视频教程
  11. linux5.8启动mysql命令_linux的定时重启的具体命令? 非常感谢。。。
  12. 笔记本无线和有线的MAC地址修改
  13. 密码学应用-身份认证+数字证书
  14. SEO技巧:Meta标签详解
  15. 【微机原理与接口 7】—— 常用指令分析4 (串操作指令剖析)
  16. 2020 最好的Linux网络监控工具(翻译)
  17. labspec6教程_LabSpec6软件功能–光谱扫描方式-Horiba.PDF
  18. STM32F10xxx中文板参考手册PDF(内有英文版链接)
  19. 光学接触角计算机软件,悬滴法表界面张力仪及接触角仪
  20. 剑指offer系列-代码的鲁棒性

热门文章

  1. python压缩文件为zip-python 压缩文件为zip后删除原文件
  2. 安卓10不支持qmc解码_官宣:安卓10已发布!21款手机已适配,小米华为率先支持...
  3. mysql 多数据源访问_通过Spring Boot配置动态数据源访问多个数据库的实现代码
  4. linux智能电压表设计与实现,毕业论文 智能数字电压表设计.doc
  5. weblogic启动项目报错找不到类_启动类报错是经常出现的事但是单一的从一个地方找原因会越找越错...
  6. 计算机系统集成难点,企业MES实施中存在的难点及建议
  7. Python处理csv文件
  8. create-react-app 使用代理做 mock
  9. 常用注入 Script 方法
  10. Leetcode刷题(4)罗马数字转整数