tcp连接+套接字编程

news2025/1/19 10:23:27

tcp头部

tcp端口号

TCP的连接是需要四个要素确定唯一一个连接:
(源IP,源端口号)+ (目地IP,目的端口号)
所以TCP首部预留了两个16位作为端口号的存储,而IP地址由上一层IP协议负责传递
源端口号和目地端口各占16位两个字节,也就是端口的范围是2^16=65535
另外1024以下是系统保留的端口,从1024-65535是用户使用的端口范围

tcp序号和确认号

32位序号 seq:Sequence number 缩写seq ,TCP通信过程中某一个传输方向上的字节流的每个字节的序号,通过这个来确认发送的数据有序,比如现在序列号为1000,发送了1000,下一个序列号就是2000。

32位确认号 ack:Acknowledge number 缩写ack,TCP对上一次seq序号做出的确认号,用来响应TCP报文段,给收到的TCP报文段的序号seq加1,即表示期待下一次发送的序号

tcp标志位

每个TCP段都有一个目的,这是借助于TCP标志位选项来确定的,允许发送方或接收方指定哪些标志应该被使用,以便段被另一端正确处理。
用的最广泛的标志是 SYNACK 和 FIN,用于建立连接,确认成功的段传输,最后终止连接。

  1. SYN:简写为S,同步标志位,用于建立会话连接,同步序列号;
  2. ACK: 简写为.,确认标志位,对已接收的数据包进行确认,1表示确认号有效,0表示报文中不包含确认信息;
  3. FIN: 简写为F,完成标志位,表示我已经没有数据要发送了,即将关闭连接;
  4. PSH:简写为P,推送标志位,表示该数据包被对方接收后应立即交给上层应用,而不在缓冲区排队;
  5. RST:简写为R,重置标志位,用于连接复位、拒绝错误和非法的数据包;
  6. URG:简写为U,紧急标志位,表示数据包的紧急指针域有效,用来保证连接不被阻断,并督促中间设备尽快处理;

tcp的三次握手

第一次握手
客户端将TCP报文标志位SYN置为1,随机产生一个序号值seq=x,将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT状态,等待服务器端确认。

第二次握手
服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将TCP报文标志位SYN和ACK都置为1,ack=x+1,随机产生一个序号值seq=y,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。

第三次握手
客户端收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

为什么连接的建立需要三次握手?

假设client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。

假设采用的是“两次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。

tcp的四次挥手

第一次挥手: Client端发起挥手请求,向Server端发送标志位是FIN报文段,设置序列号seq,此时,Client端进入FIN_WAIT_1状态,这表示Client端没有数据要发送给Server端了。

第二次分手:Server端收到了Client端发送的FIN报文段,向Client端返回一个标志位是ACK的报文段,ack设为seq加1,Client端进入FIN_WAIT_2状态,Server端告诉Client端,我确认并同意你的关闭请求。

第三次分手: Server端向Client端发送标志位是FIN的报文段,请求关闭连接,同时Client端进入LAST_ACK状态。

第四次分手 : Client端收到Server端发送的FIN报文段,向Server端发送标志位是ACK的报文段,然后Client端进入TIME_WAIT状态。Server端收到Client端的ACK报文段以后,就关闭连接。此时,Client端等待2MSL的时间后依然没有收到回复,则证明Server端已正常关闭,那好,Client端也可以关闭连接了。

为什么连接的关闭需要四次挥手?

由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式。这就意味着,关闭连接时,当Client端发出FIN报文段时,只是表示Client端告诉Server端数据已经发送完毕了。当Server端收到FIN报文并返回ACK报文段,表示它已经知道Client端没有数据发送了,但是Server端还是可以发送数据到Client端的,所以Server很可能并不会立即关闭SOCKET,直到Server端把数据也发送完毕。当Server端也发送了FIN报文段时,这个时候就表示Server端也没有数据要发送了,就会告诉Client端,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么要等待2MSL?

第一点:保证TCP协议的全双工连接能够可靠关闭
由于IP协议的不可靠性或其它网络原因,导致了Server端没有收到Client端的ACK报文,发生超时。那么Server重发FIN,如果此时Client端的连接关闭了,则重发的FIN就找不到对应的连接,导致连接错乱。

第二点:保证这次连接的重复数据段从网络中消失
如果Client端发送最后的ACK后直接进入CLOSED状态,然后又再向Server端发起一个新连接,这时如果新老连接的端口号如果相同。

那么就可能出现问题:如果老连接某些数据滞留在网络中,这些延迟数据在建立新连接后到达Client端,由于新老连接的端口号和IP都一样,TCP协议就认为延迟数据是属于新连接的,新连接就会接收到脏数据,这样就会导致数据包混乱。

接口认识

创建套接字(客户端&服务器)

 创建套接字首先得选择使用什么协议簇得套接字,比如使用ipv4协议(AF_INET)还是使用ipv6协议(AF_INET6)。其次选择该套接字的类型,是使用面向字节流(SOCK_STREAM)还是面向数据报(SOCK_DGRAM)的套接字。第三个参数一般是置为0的

该结果的返回值:成功return一个新的socket的文件描述符(fd),失败则返回-1。

绑定套接字(服务器)

绑定套接字需要选择绑定哪一个套接字(未建立连接),其次选择该套接字使用什么地址簇,绑定哪个端口,绑定哪个ip。第三个参数是第二个结构参数的大小。 

关于第二个参数,这里有必要说明一下。各种网络协议的地址格式并不相同。IPv4地址用sockaddr_in结构体表示。大多时候,我们也是基于ipv4编程。下边是关于sockaddr_in结构体的介绍。

地址簇的选择一般是选择AF_INET,即ipv4。

端口号的绑定,还需要介绍一下,这里我们的端口号是基于主机序列的,而我们需要将主机序列的端口号转换为网络序列进行绑定。需要使用htons()函数。htons()作用是将端口号由主机字节序转换为网络字节序的整数值,(host to net)

htonl()作用和htons()一样,不过它针对的是32位的(long),而htons()针对的是16位的(short)。

与htonl()和htons()作用相反的两个函数是:ntohl()和ntohs()。

ip地址的绑定,这里还有一个in_addr的结构体。

我们传过去的ip地址一般都是点分十进制的,是便于我们识别的一种形式,需要将其转换成网络序列。inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值。一般需要转换成为网络序列的是客户端。作为服务端,需要接受所有发向该主机的该端口的数据。(一台主机可能配置多个ip)。因此:INADDR_ANY的宏值绑定在ip地址上就能解决这种问题。

监听套接字(服务器)

 listen的第二个参数是监听队列大小。

Linux内核协议栈为一个tcp连接管理使用两个队列:

1. 半链接队列(用来保存处于SYN_SENT和SYN_RECV状态的请求)

2. 全连接队列(accpetd队列)(用来保存处于established状态,但是应用层没有调用accept取走的请求

而全连接队列的长度会受到 listen 第二个参数的影响。

接收套接字(服务器)

首先选择从哪个欢迎套接字接收新的套接字,其次该套接字使用什么类型的网络协议结构, 第三个参数是第二个结构体的大小(注意其类型)。

连接套接字(客户端)

首先选择连接该套接字的fd,其次选择该套接字使用什么格式的网络地址簇,端口是什么。第三个参数是第二个参数结构体的大小。 

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

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

相关文章

autoware.ai感知随笔--地面滤波

autwoware.ai中点云预处理–points_preprocessor points_preprocessor cloud_transformer: 点云坐标转换,将输入的点云转化为velodyne坐标系下的点云。 compare_map_filter: 对比激光雷达点云和点云地图,然后提取(或去除)一致的点。 |input_…

联通面试题

一、GC 1.1、目标 GC的主要作用是自动识别和释放不再使用的对象,回收其所占用的内存,以防止内存泄漏和内存溢出的问题。 1.2、如何实现 1.2.1、标记阶段 GC从根对象(如线程栈中的引用、静态变量等)开始,通过可达性…

CnosDB 签约京清能源,助力分布式光伏发电解决监测系统难题。

近日,京清能源采购CnosDB,升级其“太阳能光伏电站一体化监控平台”。该平台可以实现电站设备统一运行监控,数据集中管理,为操作人员、维护人员、管理人员提供全面、便捷、差异化的数据和服务。 京清能源集团有限公司(…

【LeetCode】35.复杂链表的复制

题目 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。 示例 1: 输入:head [[7,null],[13,0],[11,4]…

并发-Executor框架笔记

Executor框架 jdk5开始,把工作单元与执行机制分离开来,工作单元包括Runable和Callable,执行机制由Executor框架来提供。 Executor框架简介 Executor框架的两级调度模型 Java线程被一对一映射为本地操作系统线程 java线程启动会创建一个本…

Linux单列模式实现线程池

目录 一、单列模式 1.1 单列模式概念以及实现条件 1.2 饿汉模式 1.1.1 饿汉模式代码实现 1.1.2 饿汉模式特征和优缺点 1.3 懒汉模式 1.3.1 懒汉模式代码实现 1.3.2 懒汉模式特征以及优缺点 二、线程池 2.1 线程池概念 2.2 实现简单线程池逻辑 2.3 模拟实现懒汉模式线程…

【八大经典排序算法】:直接插入排序、希尔排序实现 ---> 性能大比拼!!!

【八大经典排序算法】:直接插入排序、希尔排序实现 ---> 性能大比拼!!! 一、 直接插入排序1.1 插入排序原理1.2 代码实现1.3 直接插入排序特点总结 二、希尔排序 ( 缩小增量排序 )2.1 希尔排序原理2.2 代码实现2.3 希尔排序特点…

UE5、CesiumForUnreal实现瓦片坐标信息图层效果

文章目录 1.实现目标2.实现过程2.1 原理简介2.2 cesium-native改造2.3 CesiumForUnreal改造2.4 运行测试3.参考资料1.实现目标 参考CesiumJs的TileCoordinatesImageryProvider,在CesiumForUnreal中也实现瓦片坐标信息图层的效果,便于后面在调试地形和影像瓦片的加载调度等过…

【C++入门到精通】C++入门 ——搜索二叉树(二叉树进阶)

阅读导航 前言一、搜索二叉树简介1. 概念2. 基本操作⭕搜索操作🍪搜索操作基本代码(非递归) ⭕插入操作🍪插入操作基本代码(非递归) ⭕删除操作🍪删除操作基本代码(非递归&#xff0…

给老婆写的,每日自动推送暖心消息

文章の目录 一、起因二、环境准备三、创建nestjs项目四、控制器五、service服务层1、获取Access token2、组装模板消息数据3、获取下次发工资还有多少天4、获取距离下次结婚纪念日还有多少天5、获取距离下次生日还有多少天6、获取时间日期7、获取是第几个结婚纪念日8、获取相恋…

前端面试题JS篇(4)

浏览器缓存 浏览器缓存分为强缓存和协商缓存,当客户端请求某个资源时,获取缓存的流程如下: 先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,则直接从本地获取缓存资源,不会发请求到服务…

vivado xpm 使用和封装

vivado xpm 使用和封装 tools -> language templates

【JavaScript】WebAPI入门到实战

文章目录 一、WebAPI背景知识1. 什么是WebAPI?2. 什么是API? 二、DOM基本概念三、获取元素三、事件初识1. 点击事件2. 键盘事件 四、操作元素1. 获取/修改元素内容2. 获取/修改元素属性3. 获取/修改表单元素属性4. 获取/修改样式属性 五、操作节点1. 新增…

scratch还原轨迹 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试四级真题和答案解析

目录 scratch还原轨迹 一、题目要求 1、准备工作 2、功能实现 二、案例分析

Python:安装Flask web框架hello world

安装easy_install pip install distribute 安装pip easy_install pip 安装 virtualenv pip install virtualenv 激活Flask pip install Flask 创建web页面demo.py from flask import Flask app Flask(__name__)app.route(/) def hello_world():return Hello World! 2023if _…

基于springboot实现的rabbitmq消息确认

概述 RabbitMQ的消息确认有两种。 一种是消息发送确认。这种是用来确认生产者将消息发送给交换器,交换器传递给队列的过程中,消息是否成功投递。发送确认分为两步,一是确认是否到达交换器,二是确认是否到达队列。 第二种是消费接…

【APUE】标准I/O库

目录 1、简介 2、FILE对象 3、打开和关闭文件 3.1 fopen 3.2 fclose 4、输入输出流 4.1 fgetc 4.2 fputc 4.3 fgets 4.4 fputs 4.5 fread 4.6 fwrite 4.7 printf 族函数 4.8 scanf 族函数 5、文件指针操作 5.1 fseek 5.2 ftell 5.3 rewind 6、缓冲相关 6.…

安装samba服务器

1.实验目的 (1)了解SMB和NETBIOS的基本原理 (2)掌握Windows和Linux之间,Linux系统之间文件共享的基本方法。 2.实验内容 (1)安装samba服务器。 (2)配置samba服务器的…

Visual Studio 线性表的链式存储节点输出引发异常:读取访问权限冲突

问题: 写了一个线性表的链式存储想要输出,能够输出,但是会报错:读取访问权限冲突 分析: 当我们输出到最后倒数第二个节点时,p指向倒数第二个节点并输出; 下一轮循环:p指向倒数第二…

Helm Kubernetes Offline Deploy Rancher v2.7.5 Demo (helm 离线部署 rancher 实践)

文章目录 1. 简介2. 预备条件3. 选择 SSL 配置4. 离线安装的 Helm Chart 选项5. 下载介质6. 生成证书7. 镜像入库8. 安装 rancher9. 配置 nodeport10. 配置 ingress11. 界面访问11.1 首页预览11.2 查看集群信息11.3 查看项目空间11.4 查看节点信息 1. 简介 Rancher 是一个开源…