Linux(程序设计):55—非阻塞connect(EINPROGRESS)「建议收藏」

Linux(程序设计):55—非阻塞connect(EINPROGRESS)「建议收藏」非阻塞connect详情介绍可以参见文章:https://blog.csdn.net/qq_41453285/article/details/89890429一、非阻塞connect概述man手册connect的man手册有如下一段内容:EINPROGRESSThesocketisnonblockingandtheconnectioncannotbe…

大家好,又见面了,我是你们的朋友全栈君。

一、非阻塞connect概述

man手册

  • connect的man手册有如下一段内容:

Linux(程序设计):55---非阻塞connect(EINPROGRESS)「建议收藏」

EINPROGRESS
    The socket is nonblocking and the connection cannot be completed immediately.  It is possible to select(2) or poll(2)  for  com‐pletion  
    by  selecting  the  socket  for writing.  After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET 
    to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully  (SO_ERROR is one of
     the usual error codes listed here, explaining the reason for the failure).

 

Linux(程序设计):55---非阻塞connect(EINPROGRESS)「建议收藏」

  • 解析文档,非阻塞connect如何使用:
    • ①当我们将sock设置为非阻塞之后,使用connect去连接服务端,即使服务端开启了,connect系统调用也不会连接成功,connect而是以失败告终,并返回错误
    • ②但是非阻塞connect返回的错误是有讲究的:
      • 如果非阻塞connect返回的错误是EINPROGRESS,代表不是connect系统调用出错了,而是connect可能会在后面才会建立完整地连接(只是当前连接还没有建立完整),所以我们可以在通过给select、pol或epoll设置等待时间,来等待这个connect的连接成功,从而进一步处理
      • 如果非阻塞connect返回的错误不是EINPROGRESS,代表就是connect系统调用本身出错了,那么就可以做一些相应的错误处理了
    • ③当非阻塞connect以EINPROGRESS错误返回之后,我们可以给select、pol或epoll设置等待时间,并将客户端封装在等待可写的结构中,进一步来等待非阻塞connect客户端与服务端建立完整地连接,在等待的过程中,如果非阻塞connect建立成功了,客户端的sock_fd就会变成可写的(这个在本人的IO复用文章中介绍过,见下图)
    • ④当非阻塞connect建立成功之后还可以利用getsockopt来读取错误码并清除该socket上的错误:
      • 如果错误码为0,表示连接成功建立
      • 否则连接失败

Linux(程序设计):55---非阻塞connect(EINPROGRESS)「建议收藏」

二、非阻塞connect的移植性问题

  • 移植性问题如下:
    • 1.首先,非阻塞的socket可能导致connect始终失败
    • 2.其次,select对处于EINPROGRESS状态下的socket可能不起作用
    • 3.最后,对于出错的socket,getsockopt在有些系统(比如Linux)上返回-1,而在有些系统上(比如源自伯克利的UNIX)返回0
  • 这些问题没有一个统一的解决办法

三、编码演示案例

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <libgen.h> //for basename
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <sys/select.h>
#include <arpa/inet.h>


int setnonblocking(int fd);

int set_nonblocking_connect(const char* ip,const char* port,int time);

int main(int argc,char *argv[])
{
    //must write ip and port
    if(argc<3){
        printf("usage:./%s [ip] [port]\n",basename(argv[0]));
        exit(EXIT_FAILURE);
    }

    int cli_fd;
    if((cli_fd=set_nonblocking_connect(argv[1],argv[2],10))==-1) 
        exit(EXIT_FAILURE);

    sleep(10);
    close(cli_fd);
    exit(EXIT_SUCCESS);
}

/*****************************************************************************
 函 数 名  : setnonblocking
 功能描述  : 将参数所指的fd设置为非阻塞
 输入参数  : int fd  
 输出参数  : 无
 返 回 值  : int
            失败退出程序,成功返回fd的旧标志
 调用函数  : 
 被调函数  : 
 
 修改历史      :
  1.日    期   : 2019年12月23日
    作    者   : 江南_董少
    修改内容   : 新生成函数

*****************************************************************************/
int setnonblocking(int fd)
{
    int old_options=fcntl(fd,F_GETFL);
    int new_options=old_options|O_NONBLOCK;

    if(fcntl(fd,F_SETFL,new_options)==-1){
        perror("fcntl");
        exit(EXIT_FAILURE);
    }
    return old_options;
}

/*****************************************************************************
 函 数 名  : set_nonblocking_connect
 功能描述  : 
 输入参数  : const char* ip  
             int port        
             int time        
 输出参数  : 无
 返 回 值  : int
 调用函数  : 
 被调函数  : 
 
 修改历史      :
  1.日    期   : 2019年12月23日
    作    者   : 江南_董少
    修改内容   : 新生成函数

*****************************************************************************/
int set_nonblocking_connect(const char* ip,const char* port,int time)
{
    int sock_fd,old_options,ret_val;
    struct sockaddr_in serAddress;

    //socket
    if((sock_fd=socket(AF_INET,SOCK_STREAM,0))==-1){
        perror("socket");
        exit(EXIT_FAILURE);
    }

    //set nonblock
    old_options=setnonblocking(sock_fd);

    //init address
    bzero(&serAddress,sizeof(serAddress));
    serAddress.sin_family=AF_INET;
    serAddress.sin_port=htons(atoi(port));
    if(inet_pton(AF_INET,ip,&serAddress.sin_addr.s_addr)==-1){
        perror("inet_pton");
        exit(EXIT_FAILURE);
    }

    //connect

    //nonblocking connect success,return sock_fd
    if((ret_val=connect(sock_fd,(struct sockaddr*)&serAddress,sizeof(serAddress)))==0){
        printf("connect with server suucess\n");

        //set fd block and return
        if(fcntl(sock_fd,F_SETFL,old_options)==-1){
            perror("fcntl");
            exit(EXIT_FAILURE);
        }
        
        return sock_fd;
    }
    
    //nonblocking connect error
    else if(errno!=EINPROGRESS){
        printf("unblock connect not support\n");
        return -1;
    }

    fd_set readfds;
    fd_set writefds;
    struct timeval timeout;

    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    timeout.tv_sec=time;
    timeout.tv_usec=0;

    ret_val=select(sock_fd+1,NULL,&writefds,NULL,&timeout);
    if(ret_val<=0){
        //select error or timeout,return
        printf("connection time out\n");
        close(sock_fd);
        return -1;
    }

    //nonblocking connect fd is not ready write,return
    if(!FD_ISSET(sock_fd,&writefds)){
        printf("no events on sock_fd found\n");
        close(sock_fd);
        return -1;
    }

    int error=0;
    socklen_t length=sizeof(error);
    //get error and save to error
    if(getsockopt(sock_fd,SOL_SOCKET,SO_ERROR,&error,&length)==-1){
        perror("getsockopt");
        exit(EXIT_FAILURE);
    }
    //error is not 0,meaning connect error
    if(error!=0){
        printf("connect failed after select with the error:%d\n",error);
        close(sock_fd);
        return -1;
    }

    //connect success
    printf("connect ready after select with the socket:%d\n",sock_fd);
    //set fd block and return
    fcntl(sock_fd,F_SETFL,old_options);
    return sock_fd;
}

测试①

  • 我们使用程序去连接8888端口的服务器,但是服务器未开启,select等待10秒之后超时退出

Linux(程序设计):55---非阻塞connect(EINPROGRESS)「建议收藏」

测试②

  • 这个测试中,我们的服务器开启了8888监听端口
  • 我们客户端程序connect没有执行成功,但是返回了EINPROGRESS错误。于是在后面的select中等待非阻塞connect建立成功并且客户端fd变为可写的。接着消除错误编码并打印相关提示信息

Linux(程序设计):55---非阻塞connect(EINPROGRESS)「建议收藏」

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/160529.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 数据挖掘的9大成熟技术和应用

    数据挖掘的9大成熟技术和应用http://ihoge.cn/2018/DataMining.html数据挖掘的9大成熟技术和应用基于数据挖掘的9大主要成熟技术以及在数据化运营中的主要应用:1、决策树2、神经网络3、回归4、关联规则5、聚类6、贝叶斯分类7、支持向量机8、主成分分析9、假设检验1 决策树决策树(DecisionTree)是一种非常成熟的、普遍采用的数据挖…

    2022年6月15日
    41
  • Win 10 专业版重新激活详细操作步骤

    Win 10 专业版重新激活详细操作步骤百度经验:jingyan.baidu.com最近电脑的win10系统显示显示未激活,需要激活,用命令提示符运行slmgr.vbs-xpr查询到期状态显示处于统治状态KMS10方法/步骤1,首先,找到计算机,右键点击属性,确认你的电脑系统是否是windows10专业版(由于小编安装的是windows10专业版,所以今天就说win10专业版的激活方式),如下图所示。2,如果有朋友找不…

    2022年5月29日
    36
  • pycharm 修改镜像源_如何设置linux服务器镜像源

    pycharm 修改镜像源_如何设置linux服务器镜像源由于国外的镜像源安装Python速度较慢,选择国内的镜像速度较快,这篇文章如要讲述如何设置国内镜像源。常用镜像源:清华:https://pypi.tuna.tsinghua.edu.cn/simple阿里云:http://mirrors.aliyun.com/pypi/simple/中国科技大学https://pypi.mirrors.ustc.edu.cn/simple/方法一:…

    2022年8月29日
    2
  • qq群关系查询网站2020_qq群数据库在线查询

    qq群关系查询网站2020_qq群数据库在线查询11月18日消息,据国内安全问题反馈平台乌云爆料,腾讯QQ存在重大安全隐患,致使QQ群关系数据泄露。目前,消息称迅雷快传上已经出现大量QQ群关系数据包的下载,根据QQ群关系数据,可得知个人真实姓名、年龄、关系网等隐私数据。乌云爆料称QQ存在重大安全隐患据乌云爆料,腾讯QQ存在重大安全隐患,该安全隐患可致使腾讯QQ群关系数据泄露,而根据QQ号即可获得该人姓名经历等详细信息。目前,大量QQ用户资料面临…

    2022年9月19日
    0
  • Exploiting Visual Artifacts to Expose Deepfakes and Face Manipulations论文详记

    Exploiting Visual Artifacts to Expose Deepfakes and Face Manipulations论文详记ExploitingVisualArtifactstoExposeDeepfakesandFaceManipulations论文详记一、论文简述二、论文内容A、篡改伪影①全局一致性②光照估计③几何估计B、基于视觉伪影的分类①、完全生成脸部的检测②、DeepFakes的检测③、Face2Face的检测三、论文实验及结果一、论文简述提取眼睛、牙齿以及脸部轮廓等位置的特征来检测DeepFake视频,属于基于帧内图像伪影的检测方法,使用Logistic回归或浅层全连接网络分类,属于浅层分类器方法

    2022年5月17日
    40
  • 感觉自己不会的东西太多了,不知道如何下手?

    感觉自己不会的东西太多了,不知道如何下手?GitHub8.8kStar的Java工程师成神之路,不来了解一下吗?GitHub8.8kStar的Java工程师成神之路,真的不来了解一下吗?GitHub8.8kStar的Java工程师成神之路,真的确定不来了解一下吗?如果让我统计下,粉丝问我做多的问题是什么,这个问题肯定可以排前5,问出这个问题的朋友们遍布各个年龄段。实话说,这个问题同样也困扰过我,大概就是我刚…

    2022年7月7日
    16

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号