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

【网络编程】IO复用的应用一:非阻塞connect

  在connect连接中,若socket以非阻塞的方式进行连接,则系统内设置的TCP三次握手超时时间为0,所以它不会等待TCP三次握手完成,直接返回,错误为EINPROGRESS。
  所以,我们可以通过判断connect时返回的错误码是不是EINPROGRESS来实现非阻塞的connect,如果当前是EINPROGRESS并且socket可写,则说明链路建立成功。此时调用getsockopt来清除文件描述符上的错误信息,接下来如果没有错误信息则链路成功建立。
B站一位UP主的讲解

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>#define BUFFER_SIZE 1023int setnonblocking(int fd){  //对一个文件描述符设置非阻塞int old_option = fcntl(fd, F_GETFL); //old_option表示fd的旧文件属性int new_option = old_option | O_NONBLOCK; //在old_option上追加非阻塞属性fcntl(fd, F_SETFL, new_option); //给fd设置新属性return old_option; //返回旧属性
}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;inet_pton(AF_INET, ip, &address.sin_addr);//将点分十进制转化为网络字节序address.sin_port = htons(port);//将主机字节序转换为网络字节序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 with server immediately!\n");fcntl(sockfd, F_SETFL, fdopt);//重置sockfd属性return sockfd;}else if(errno != EINPROGRESS){ //如果连接没有立即建立,那么只有当errno时EINPROGRESS时才表示连接还在进行//否则出错返回printf("unblock connect not support!\n");return -1;}fd_set readfds;fd_set writefds;struct timeval timeout;FD_ZERO(&readfds);  //将readfds的文件描述符集合清空FD_SET(sockfd, &writefds); //将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是否在writefds的集合中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("get socket option failed\n");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){printf("usag: %s ip_address port_number\n", basename(argv[0]));return 1;}const char* ip = argv[1];int port = atoi(argv[2]);int fd = unblock_connect(ip, port, 0);if(fd < 0 ) return 1;close(fd);return 0;
}
http://www.lryc.cn/news/101781.html

相关文章:

  • Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
  • C#设计模式之---原型模式
  • STM32入门学习之外部中断
  • Jenkins 配置maven和jdk
  • Leetcode | Binary search | 22. 74. 162. 33. 34. 153.
  • 生命在于折腾——面试问题汇总
  • <Java>Map<String,Object>中解析Object类型数据为数组格式
  • 别再分库分表了,试试TiDB!
  • Java进阶之Dump文件初体验
  • 基于扩展(EKF)和无迹卡尔曼滤波(UKF)的电力系统动态状态估计(Matlab代码实现)
  • 曲线拟合(MATLAB拟合工具箱)位置前馈量计算(压力闭环控制应用)
  • 小程序使用echarts
  • 面向对象——封装
  • 【LeetCode】160.相交链表
  • 【JWT的使用】
  • Python获取音视频时长
  • TCP四次握手为什么客户端等待的时间是2MSL
  • Android Studio 启用设备远程调试配置完整步聚
  • 玩转LaTeX(三)【数学公式(基础)、​矩阵、多行公式】
  • jenkins 配置git
  • 单机部署MinIo并设置开机自启
  • Latex | 使用MATLAB生成.eps矢量图并导入Latex中的方法
  • 宝塔面板定时任务重启各种服务
  • Ansible playbook编写
  • 个人博客系统 -- 登录页面添加图片验证码
  • 剑指offer10-I.斐波那契数列
  • 13年测试经验,性能测试-压力测试指标分析总结,看这篇就够了...
  • 大数据课程D3——hadoop的Source
  • F5 LTM 知识点和实验 4-持久化
  • SpringBoot之WebMvcConfigurer详解