非阻塞connect详解

本文详细解析TCP的非阻塞connect,解释为何使用非阻塞模式,介绍其在连接失败时的处理方式,以及如何判断连接是否成功,并提供相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们先来讲connect函数(本文针对的是TCP)

#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr* servaddr, socklen_t addrlen);

参数大家应该都知道,我在这里提一下,为什么第二个参数要用 struct sockaddr*?

  • 这是因为ANSI C标准为我们定义了一个标准套接字的结构体,就是 struct sockaddr, 我们在之前声明的结构如 ipv4中struct sockaddr_in,它们的结构体长度是相同的,证明在强制转换的过程之前定义的结构体中数据没有丢失。如果我们不强制转换,编译器就会报错。

一般调用connect函数的都是客户端,客户端在调用connect之前不必非得调用bind函数进行地址绑定,因为一般内核会确定源IP地址,并选择一个临时端口作为源端口。

调用connect函数后将会激发TCP的三路握手过程

connect函数只在连接建立成功或者出错时返回,其中出错返回可能有以下几种情况

  • TCP客户没有收到SYN分节的响应,则返回ETIMEDOUT。(内核不会立即返回,而是会在固定的时间内多次发送SYN分节,如果都没有响应,则会返回错误)。
  • 如果服务端对客户的响应是RST(表示复位),则表明该服务器主机在我们指定的端口上没有进程在等待与之连接,客户一接到RST就会立即返回ECONNREFUSED错误。

RST是TCP发生错误时发送的一种分节。产生RST的三个条件:
1、目的地为某端口的SYN到达,然而该端口没有正在监听的服务器。(这就是上面描述的情况)
2、TCP想取消一个已有连接
3、TCP接收到一个根本不存在的连接上的分节。

-若客户发出的SYN分节在中间的某个路由器上引发了一个"destination unreachable"(目的地不可达)ICMP错误,则认为是一种软错误(soft error)。客户主机内核保存该消息,并按第一种情况所述的时间间隔继续发送SYN。若在某个规定时间后仍未收到响应,则把保存的消息(ICMP错误)作为EHOSTUNREACH或ENETUREACH错误返回给进程。

上文讲了这么多,那到底为什么要用非阻塞connect

那先来说说阻塞connect。在用阻塞模式的connect时,如果出现了上文中第一个错误,connect迟迟没有完成连接,用户程序就会阻塞在connect函数,一般的connect的超时时间在75秒到几分钟之间,那用户程序就需要等待这么久才能返回接着运行,这样就降低了效率。

如果使用非阻塞的connect,如果连接没有立即建立,就要判断它的错误码,我们期望的是EINPROGRESS,表示连接建立已经启动但是尚未完成。这个时候我们就要将套接字加入到select的可写事件集中,然后我们设置一个时间,这个时间就是我们想要等待连接再进行多久的时间,如果这个时间段内select返回并且套接字可写,这个时候connect也不一定成功,我们还要接着判断,因为在POSIX中套接字出错也是会变成即可读又可写的,所以我们还需要用getsockopt函数来获取错误码,如果错误码为0则表示connect成功,否则就失败。

看到这大家也应该能了解到非阻塞connect的优点了。那就是我们可以自己定义connect调用的时间,而不是阻塞的去等待系统规定的时长。

下面就是我们非阻塞connect实现的代码

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<iostream>
#include<error.h>
#include<unistd.h>
#include
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值