从抓包的角度分析connect()函数的连接过程

news2025/2/28 12:57:56

这篇文章主要是从tcp连接建立的角度来分析客户端程序如何利用connect函数和服务端程序建立tcp连接的,了解connect函数在建立连接的过程中底层协议栈做了哪些事情。

tcp三次握手

在正式介绍connect函数时,我们先来看一下tcp三次握手的过程,下面这个实验是客户端通过telnet远程登录服务端的例子,telnet协议是基于tcp协议,我们可以通过wireshark抓包工具看到客户端和服务端之间三次握手的过程,12.1.1.1是客户端的ip地址,12.1.1.2是服务端的ip地址。

 下面是我们通过wireshark抓取到的tcp三次握手的数据包:

 我们看到客户端远程登录服务端时,首先发送了一个SYN报文,其中目标端口为23(远程登录telnet协议使用23端口),初始序号seq = 0,并设置自己的窗口rwnd = 4128(rwnd是一个对端通告的接收窗口,用于流量控制)

然后服务端回复了一个SYN + ACK报文,初始序号seq = 0ack = 1(在前一个包的seq基础上加1),同时也设置自己的窗口rwnd = 4128

然后客户端收到服务端的SYN + ACK报文时,回复了一个ACK报文,表示确认建立tcp连接,序号为seq = 1, ack = 1(在前一个包的seq基础上加1), 设置窗口rwnd = 4128,此时客户端和服务端之间已经建立tcp连接。

connect函数

前面我们在介绍tcp三次握手的时候说过,客户端在跟服务端建立tcp连接时,通常是由客户端主动向目标服务端发起tcp连接建立请求,服务端被动接受tcp连接请求;同时服务端也会发起tcp连接建立请求,表示服务端希望和客户端建立连接,然后客户端会接受连接并发送一个确认,这样双方就已经建立好连接,可以开始通信。

这里说明一下:可能有的小伙伴会感到疑惑,为啥服务端也要跟客户端建立连接呢?其实这跟tcp采用全双工通信的方式有关。对于全双工通信,简单来说就是两端可以同时收发数据,如下图所示:

 我们再回到正题,那么在网络编程中,肯定也有对应的函数做到跟上面一样的事情,没错,就是connect(连接)。顾名思义,connect函数就是用于客户端程序和服务端程序建立tcp连接的。

一般来说,客户端使用connect函数跟服务端建立连接,肯定要指定一个ip地址和端口号(相当于客户端的身份标识),要不然服务端都不知道你是谁?凭什么跟你建立连接。同时还得指明服务端的ip地址和端口号,也就是说,你要跟谁建立连接。

connect函数原型:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:
sockfd:客户端的套接字文件描述符
addr:要连接的套接字地址,这是一个传入参数,指定了要连接的套接字地址信息(例如IP地址和端口号)
addrlen:是一个传入参数,参数addr的大小,即sizeof(addr)

返回值说明:连接建立成功返回0,失败返回-1并设置errno

connect函数在建立tcp连接的过程中用到了一个非常重要的队列,那就是未决连接队列,这个队列用来管理tcp的连接,包括已完成三次握手的tcp连接和未完成三次握手的tcp连接,下面我们就来详细介绍一下未决连接队列。

未决连接队列
未决连接队列是指服务器接收到客户端的连接请求,但是尚未被处理(也就是未被accept,后面会说)的连接,可以理解为未决连接队列是一个容器,这个容器存储着这些尚未被处理的链接。

当一个客户端进程使用 connect 函数发起请求后,服务器进程就会收到连接请求,然后检查未决连接队列是否有空位,如果未决队列满了,就会拒绝连接,那么客户端调用的connect 函数返回失败。

如果未决连接队列有空位,就将该连接加入未决连接队列。当 connect 函数成功返回后,表明tcp的“三次握手”连接已完成,此时accept函数获取到一个客户端连接并返回。

 在上图中,在未决连接队列中又分为2个队列:

未完成队列(未决队列):即客户端已经发出SYN报文并到达服务器,但是在tcp三次握手连接完成之前,这些套接字处于SYN_RCVD状态,服务器会将这些套接字加入到未完成队列。

已完成队列:即刚刚完成tcp三次握手的tcp连接,这些套接字处于ESTABLISHED状态,服务器会将这些套接字加入到已完成队列。

相关视频推荐

4个小时搞懂tcp/ip协议栈,从tcp/ip协议栈原理到实现一个网络协议栈

c++八股文重点,网络的posix api实现原理

10道面试必问的经典网络八股文,让你在面试中逼格满满

 免费学习地址:

C/C++Linux服务器开发/后台架构师

需要C/C++ Linux服务器架构师学习资料加群812855908(资料包括C/C++,Linux,golang技术,内核,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)

 我们来看一下连接建立的具体过程,如图所示:

 服务端首先调用listen函数监听客户端的连接请求,然后调用accept函数阻塞等待取出未决连接队列中的客户端连接,如果未决连接队列一直为空,这意味着没有客户端和服务器建立连接,那么accept就会一直阻塞。

当客户端一调用connect函数发起连接时,如果完成tcp三次握手,那么accept函数会取出一个客户端连接(注意:是已经建立好的连接)然后立即返回。

上面就是客户端和服务端在网络中的状态变迁的具体过程,前面我们在学习tcp三次握手的过程中还知道,服务端和客户端在建立连接的时候会设置自己的一个接收缓冲区窗口rwnd的大小。

服务端在发送SYN + ACK数据报文时会设置并告知对方自己的接收缓冲区窗口大小,客户端在发送ACK数据报文时也会设置并告知对方自己的接收缓冲区窗口大小。

注意,accept函数调用成功,返回的是一个已经完成tcp三次握手的客户端连接。如果在三次握手的过程中(最后一步),服务端没有接收到客户端的ACK,则说明三次握手还没有建立完成,accept函数依然会阻塞。

关于tcp三次握手连接建立的几种状态:SYN_SENTSYN_RCVDESTABLISHED
SYN_SENT:当客户端调用connect函数向服务端发送SYN包时,客户端就会进入 SYN_SENT状态,并且还会等待服务器发送第二个SYN + ACK包,因此SYN_SENT状态就是表示客户端已经发送SYN包。

SYN_RCVD:当服务端接收到客户端发送的SYN包并确认时,服务端就会进入 SYN_RCVD状态,这是tcp三次握手建立的一个很短暂的中间状态,一般很难看到, SYN_RCVD状态表示服务端已经确认收到客户端发送的SYN包。

ESTABLISHED:该状态表示tcp三次握手连接建立完成。

对于这两个队列需要注意几点注意:

1. 未完成队列和已完成队列的总和不超过listen函数的backlog参数的大小。listen函数的签名如下:

int listen(int sockfd, int backlog);

2. 一旦该连接的tcp三次握手完成,就会从未完成队列加入到已完成队列中

3. 如果未决连接队列已满,当又接收到一个客户端SYN时,服务端的tcp将会忽略该SYN,也就是不会理客户端的SYN,但是服务端并不会发送RST报文,原因是:客户端tcp可以重传SYN,并期望在超时前未决连接队列找到空位与服务端建立连接,这当然是我们所希望看到的。如果服务端直接发送一个RST的话,那么客户端的connect函数将会立即返回一个错误,而不会让tcp有机会重传SYN,显然我们也并不希望这样做。

但是不排除有些linux实现在未决连接队列满时,的确会发送RST。但是这种做法是不正确的,因此我们最好忽略这种情况,处理这种额外情况的代码也会降低客户端程序的健壮性。

connect函数出错情况

由于connect函数是在建立tcp连接成功或失败才返回,返回成功的情况本文上面已经介绍过了。这里我们介绍connect函数返回失败的几种情况:
第一种
当客户端发送了SYN报文后,没有收到确认则返回ETIMEDOUT错误,值得注意的是,失败一次并不会马上返回ETIMEDOUT错误。即当你调用了connect函数,客户端发送了一个SYN报文,没有收到确认就等6s后再发一个SYN报文,还没有收到就等24s再发一个(不同的linux系统设置的时间可能有所不同,这里以BSD系统为主)。这个时间是累加的,如果总共等了75s后还是没收到确认,那么客户端将返回ETIMEDOUT错误。

对于linux系统,改变这个系统上限值也比较容易,由于需要改变系统配置参数,你需要root权限。
相关的命令是sysctl net.ipv4.tcp_syn_retries(针对于ipv4)。
在设置该值时还是要比较保守的,因为每次syn包重试的间隔都会增大(比如BSD类的系统实现中间隔会以2到3倍增加),所有tcp_syn_retries的一个微小变化对connect超时时间的影响都非常大,不过扩大这个值也不会有什么坏处,因为你代码中设置的超时值都能够生效。但是如果代码中没有设置connect的超时值,那么connect就会阻塞很久,你发现对端机器down掉的间隔就更长。
作者建议设置这个值到6或者7,最多8。6对应的connect超时为45s,7对应90s,8对应190s。

你能通过以下命令修改该值:

sysctl -w net.ipv4.tcp_syn_retries=6

查看该值的命令是:

sysctl net.ipv4.tcp_syn_retries

如果希望重启后生效,将net.ipv4.tcp_syn_retries = 6放入/etc/sysctl.conf中。

这种情况一般是发生在服务端的可能性比较大,也就是服务端当前所处网络环境流量负载过高,网络拥塞了,然后服务端收到了客户端的SYN报文却来不及响应,或者发送的响应报文在网络传输过程中老是丢失,导致客户端迟迟收不到确认,最后返回ETIMEDOUT错误。

我们可以简单复现一下这种情况,这个实验是基于CentOS系统进行的,具体过程如下所示:

1. 首先通过iptables -F把Centos上的防火墙规则清理掉,然后再通过iptables -I INPUT -p tcp --syn -i lo -j DROP命令把本地的所有SYN包都过滤掉(模拟服务端当前网络不稳定)。

执行以下命令:

1iptables -F
2iptables -I INPUT -p tcp --syn -i lo -j DROP

2. 然后通过nc命令向本地的环回地址127.0.0.1发起tcp连接请求(相当于自己跟自己发起tcp连接),来模拟客户端跟服务端发起tcp连接,但是服务器端就是不响应,最后导致客户端的tcp连接建立请求超时,并终止tcp连接。

 3. 然后再通过tcpdump工具把客户端和服务端建立tcp连接过程中的数据报都抓取下来,由于我们设置的服务器侦听端口号是10086,这里我们可以通过tcpdump -i any port 10086命令来过滤所有网卡的10086端口的数据包。

 如上图所示,localhost.39299代表客户端,localhost.10086代表服务端,客户端总共向服务端发送了6个SYN报文,这6个SYN包的间隔时间分别是1s,2s,4s,8s,16s,这些时间累积加起来总共为31s,其实客户端在发送最后一个SYN报文时还等待了一段时间,然后才超时。也就是说,客户端在发送了第一个SYN报文时,会设置了一个计时器并开始计时,在最后一个SYN报文还没收到服务端的确认时,这个计时器就会超时,然后关闭tcp连接。

第二种
客户端连接一个服务器没有侦听的端口。

过程是:客户端发送了一个SYN报文后,然后服务端回复了一个RST报文,说明这是一个异常的tcp连接,服务端发送了RST报文重置这个异常的tcp连接。

这种情况一般为拒绝连接请求,比如:客户端想和服务端建立tcp连接,但是客户端的连接请求中使用了一个不存在或没有侦听的端口(比如:这个端口超出65535的范围),那么服务端就可以发送RST报文段拒绝这个请求。

 拒绝连接一般是由服务器主动发起的,因为客户端发起请求连接携带的目的端口,可能服务器并没有开启LISTEN状态。因此服务器在收到这样的报文段后会发送一个RST报文段,在这个报文里把RSTACK都置为1,它确认了SYN报文段并同时重置了该tcp连接,然后服务器等待另一个连接。客户端在收到RST+ACK报文段后就会进入CLOSED状态。

这里以通过20000不存在的端口远程登录为例:

 tcpdump抓取到的数据包如下:

113:35:08.609549 IP 192.168.98.137.49057 > 192.168.0.102.dnp: Flags [S], seq 2919679902, win 14600, options [mss 1460,sackOK,TS val 39134059 ecr 0,nop,wscale 6], length 0
213:35:09.610018 IP 192.168.98.137.49057 > 192.168.0.102.dnp: Flags [S], seq 2919679902, win 14600, options [mss 1460,sackOK,TS val 39135059 ecr 0,nop,wscale 6], length 0
313:35:09.610115 IP 192.168.0.102.dnp > 192.168.98.137.49057: Flags [R.], seq 1766537774, ack 2919679903, win 64240, length 0
413:35:10.610188 IP 192.168.0.102.dnp > 192.168.98.137.49057: Flags [R.], seq 3482791532, ack 1, win 64240, length 0

通过分析tcpdump工具抓取的数据发现,RST报文段不携带数据。

第三种
如果客户端调用connect函数向服务端发送了一个SYN报文,这个SYN报文在网络传输过程中经过某个路由器时,正好这个路由器出问题了,缺少到达目的地的路由,不能把这个SYN报文转发给目的地址,那么该路由器会丢弃这个SYN报文,并同时给客户端发送一个Destination unreachable(主机不可达)的ICMP差错报文。客户端的linux内核会保存这个Destination unreachable的ICMP差错报文,同时按第一种情况继续发送SYN报文,如果在规定的时间超时后还没收到服务端的响应报文,那么linux内核会把保存的ICMP差错报文作为EHOSTUNREACHENETUNREACH错误返回给客户端的应用进程。

下面的这个实验就是用来说明第三种情况,帮助理解,大家能看明白就行了,可以不用去做这个实验,当然,有兴趣的同学可以去模拟一下。

 然后client远程登录server成功。

 上图中没有指定telnet端口号,使用默认端口号23。

这是抓取到的数据包,client在远程登录server时,发起了SYN连接请求。

 现在我们来模拟client设备出故障,删除R1设备到server的路由信息

no ip route 12.1.3.0 255.255.255.0 12.1.2.2

client再登录server时就会失败,我们从抓取到的数据包可以发现,client发送了一个SYN报文,然后R1设备收到这个SYN报文时,发现自己不能到达server,于是会把这个SYN报文丢弃掉,并向client发送了一个目标主机不可达的ICMP差错报文,于是client发送了RST报文来关闭这条异常的tcp连接。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/426630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用孕妇的思维和孕妇对话——《用孩子的思维和孩子对话》

看惯了某鱼上经典的卖货话术,“不懂事怀孕了,遂出”。没想到我居然也快要当爸爸了。这几个月准爸爸的生活让我切身的体会到了孕妇的不容易以及陪伴孕妇的辛苦。本文不打算歌颂母亲或者替准爸爸们倒苦水,单纯总结思考一下孕期夫妻如何沟通。加…

360度全景拍摄,探索全景世界带你飞跃视野新高度

引言: 随着科技的不断发展和进步,数字媒体技术也得到了长足的发展和应用。其中,全景拍摄作为数字媒体领域的一项创新技术,能够为人们提供更加直观、真实和生动的视觉体验,广泛应用于旅游、房地产、商业推广和教育培训…

【牛客网】树根与星际密码

目录 一、编程题 1.树根 2.星际密码 二、选择题 一、编程题 1.树根 链接:数根__牛客网 (nowcoder.com) 数根可以通过把一个数的各个位上的数字加起来得到。如果得到的数是一位数,那么这个数就是数根;如果结果是两位数或者包括更多位的数…

【瑞吉外卖】001 -- 项目介绍与环境搭建

本文章为对 黑马程序员Java项目实战《瑞吉外卖》的学习记录 项目效果展示: 目录 一、软件开发整体介绍 1、软件开发流程 2、角色分工 3、软件环境 二、瑞吉外卖项目介绍 1、项目介绍 2、产品原型展示 3、技术选型 4、功能架构 5、角色 三、开发环境搭建 1、数据库环…

matlab升余弦滤波器comm.RaisedCosineTransmitFilter用法

RaisedCosineTransmitFilter是一个MATLAB通信工具箱中的函数,用于上采样和滤波输入信号。它可以使用正常的升余弦FIR滤波器或平方根升余弦FIR滤波器。通过使用升余弦FIR插值信号来应用脉冲整形滤波器。系统对通过使用升余弦有限脉冲响应(FIR)滤波器对输入信号进行插…

基于libevent实现调度器

一、调度器 1、调度器要解决的问题 1)事件保序 2)实现异步接口 2、调度器实现原理 调度器主要由下面的几个部件构成,如下: 2.1、Job 功能:保存回调及自定义参数 2.2、JobDescriptor 功能:1)创建…

从编译角度看c和c++混合编译

往期地址: 操作系统系列一 —— 操作系统概述操作系统系列二 —— 进程操作系统系列三 —— 编译与链接关系操作系统系列四 —— 栈与函数调用关系操作系统系列五——目标文件详解操作系统系列六 —— 详细解释【静态链接】 本期主题: c和c混合编译 C和…

【蓝桥杯】计算指定日期为当年第几天

文章目录前言题目分析算法难度实战1、创建算法2、创建测试用例3、测试结果总结前言 蓝桥杯全国软件和信息技术专业人才大赛由工业和信息化部人才交流中心主办,每年参赛人数超过30000人。蓝桥杯大赛作为国内领先的全国性 IT 学习赛事,持续有力支撑综合测评、奖学金评…

Web前端开发:HTML、CSS

一. 前端开发介绍 在介绍Web网站工作流程的时候提到,前端开发,主要的职责就是将数据以好看的样式呈现出来,说白了,就是开发网页程序,如下图所示:1. 网页有哪些部分组成 ? 文字、图片、音频、视频、超链接…

车企跨界背后,智能手机进入新增长时代

2022年中国智能手机销量首次跌破了3亿部大关,创下了十年来的最低水平。与此同时,以新能源车和XR为代表的新形态终端日渐成为新宠。在行业内外部多重因素影响之下,“唱衰”智能手机的声音也在甚嚣尘上,甚至有不少人认为智能机已进入…

笔记本电脑开不了机?3种解决方法

案例:笔记本电脑开不了机怎么办? 【我的笔记本电脑一直用得好好的,今天突然开不了机,尝试按了开机键很多次也没有解决。有人遇到过同样的问题吗?有没有解决的方法!】 在日常生活中,我们经常会…

Vulnhub靶场DC1-2练习

目录0x00 准备0x01 信息收集0x02 漏洞利用与攻击0x03 思路总结0x00 准备 下载连接:https://download.vulnhub.com/dc/DC-2.zip 介绍:Just like with DC-1, there are five flags including the final flag.Please note that you will need to set the …

看完这篇文章你就彻底懂啦{保姆级讲解}-----(I.MX6U驱动LED灯《使用汇编语言编写》) 2023.4.17

目录前言STM32 知识回顾完整汇编代码最终编译验证结束语前言 首先我们在开发stm32的时候驱动LED灯会有两种方式,分别是寄存器和库函数版本。因为在实际的开发过程中,我们更愿意更习惯用库函数版本来驱动各种外设,但是对于底层的寄存器调用和…

Linux宝塔安装msyql服务,默认密码,允许远程登录问题解决

一、首先我在宝塔安装mysql服务是5.7 1.1MySQL数据库5.6之前(不包括)默认密码为空,用户不用输入密码,直接回车登陆 mysql -uroot -p password:(空) 1.2.MySQL数据库5.6之后(包括)默认密码是MySQL数据库随机…

Mybatis手动配置ORM,不用自动ORM等操作

一、解决mapper.xml存放在resources以外路径中的读取问题 在pom.xml文件最后追加< build >标签&#xff0c;以便可以将xml文件复制到classes中&#xff0c;并在程序运行时正确读取。 <build><!-- 如果不添加此节点src/main/java目录下的所有配置文件都会被漏掉…

【Android Audio】TimeCheck机制

TimeCheck机制&#xff08;Android R/S&#xff09; TimeCheck.cpp TimeCheck.h frameworks/av/media/utils/TimeCheck.cpp TimeCheck守护线程的作用&#xff1a; 当audioserver中IAudioFlinger&#xff0c;IAudioPolicyService&#xff0c;IEffect中的每一个binder函数调用时…

Web 攻防之业务安全:Callback自定义测试(触发XSS漏洞)

Web 攻防之业务安全&#xff1a;Callback自定义测试 业务安全是指保护业务系统免受安全威胁的措施或手段。广义的业务安全应包括业务运行的软硬件平台&#xff08;操作系统、数据库&#xff0c;中间件等&#xff09;、业务系统自身&#xff08;软件或设备&#xff09;、业务所提…

学习C语言十天了,我实现了仿真自由落体小球『C/C++图形库EasyX』

文章目录&#x1f490;专栏导读文章导读准备工作一、显示一个静止的小球二、显示多个小球使用#define美化代码三、小球下落动画四、利用while循环实现小球下落五、利用if语句实现小球重复下落六、实现小球落地反弹七、实现小球加速下落&#x1f490;专栏导读 &#x1f338;作者…

剪枝与重参第七课:YOLOv8剪枝

目录YOLOv8剪枝前言1.Overview2.Pretrain(option)3.Constrained Training4.Prune4.1 检查BN层的bias4.2 设置阈值和剪枝率4.3 最小剪枝Conv单元的TopConv4.4 最小剪枝Conv单元的BottomConv4.5 Seq剪枝4.6 Detect-FPN剪枝4.7 完整示例代码5.YOLOv8剪枝总结总结YOLOv8剪枝 前言 …

【三十天精通Vue 3】第八天 Vue 3 生命周期钩子详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录引言一、Vue 3 生命周期钩子概述1.1 生命周期钩子的简介1.2 生命周…