【Linux】TCP协议【下三】{面向字节流/粘包问题/TCP异常情况/文件和Socket}

news2024/12/22 20:21:09

文章目录

  • 7.面向字节流
    • TCP(传输控制协议)和UDP(用户数据报协议)
  • 8.粘包问题
  • 9.TCP异常情况
  • 10.再谈文件和socket的关系

7.面向字节流

创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;一个链接一对发收缓冲区。
调用write时, 数据会先写入发送缓冲区中;
如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出
去;
接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
然后应用程序可以调用read从接收缓冲区拿数据;
另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可
以写数据. 这个概念叫做 全双工
由于缓冲区的存在, TCP程序的读和写不需要一一匹配, 例如:
写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;
读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次
read一个字节, 重复100次

TCP(传输控制协议)和UDP(用户数据报协议)

是两种在计算机网络中广泛使用的传输层协议,它们在数据传输方式上有显著的区别。以下是TCP面向字节流和UDP面向数据报的具体区别:

  1. 面向字节流与面向数据报

TCP面向字节流:TCP将应用程序的数据视为无结构的字节流。这意味着TCP不关心数据是如何被组织成报文的,它只关注如何可靠地、按顺序地传输这些字节。TCP会在发送端将字节流拆分成多个(segment),并在接收端重新组合这些段以恢复原始的数据流。这种机制使得TCP能够处理任意大小的数据,同时也可能导致“粘包”问题,即多个数据块被合并成一个数据块传输。用户层认为我将4个http请求发给了对方,经过tcp层时tcp只认为只是一段二进制字节流。对方接收缓冲区收到数据也只有字节的概念,不关心是什么协议,是什么报文格式,取多少数据由用户层自定义,显然,用户层需要对接收到的数据进行控制以便能读到完整的报文而不是半个报文(例如之前编写过的网络版本计算器)。比如,发送想发送helloworld,可能hello先被接收方收到了,此时接收方用户层会识别到这不是一个完整的报文,他会继续读接收缓冲区直到把world也读了。

UDP面向数据报:UDP则不同,它将每个数据块视为一个独立的数据报(datagram)。每个数据报都包含完整的源地址和目的地址信息,以及一个可选的校验和。UDP不对数据报进行拆分或合并,而是直接将其发送到网络上。如果数据报太大而无法通过某个网络链路,那么IP层会对其进行分片(fragmentation),但这与UDP协议本身无关。在接收端,UDP会按照数据报的边界来接收数据,即每个read调用都会接收到一个完整的数据报(如果缓冲区足够大的话)。

  1. 可靠性

TCP可靠传输:TCP是一种可靠的传输协议,它通过确认应答、超时重传、流量控制等机制来确保数据的可靠传输。TCP会要求接收方对每个接收到的数据段进行确认,如果发送方在一定时间内没有收到确认,就会重新发送该数据段。此外,TCP还使用滑动窗口机制来进行流量控制,以防止发送方发送过多的数据导致接收方无法处理。
UDP不可靠传输:UDP则是一种不可靠的传输协议,它不提供任何形式的确认应答、超时重传或流量控制机制。UDP发送的数据报可能会丢失、乱序或重复到达接收方。因此,在使用UDP时,需要由应用层来负责数据的可靠性控制

  1. 连接管理

TCP面向连接:TCP是一种面向连接的协议,它在数据传输之前需要先建立连接。连接建立过程包括三次握手(SYN-SYNACK-ACK),以确保双方都准备好进行数据传输。在数据传输过程中,TCP会保持这个连接直到数据传输完成,并通过四次挥手(FIN-ACK-FIN-ACK)来关闭连接。
UDP无连接:UDP则是一种无连接的协议,它在发送数据之前不需要建立连接。UDP发送方只需要知道接收方的IP地址和端口号,就可以直接发送数据报。这种无连接的特性使得UDP在需要快速响应或广播通信的场景中非常有用。

  1. 性能与资源消耗

TCP性能与资源消耗:TCP由于需要建立连接、进行确认应答和流量控制等操作,因此相对于UDP来说会有更大的性能开销和资源消耗。但是,这种开销换来了更高的数据可靠性和有序性。
UDP性能与资源消耗:UDP则具有较低的性能开销和资源消耗,因为它不需要建立连接、进行确认应答和流量控制等操作。这使得UDP在需要高速传输或实时性要求较高的场景中更加适用。但是,UDP的可靠性和有序性较差,需要由应用层来负责数据的可靠性控制。
综上所述,TCP面向字节流和UDP面向数据报在数据传输方式、可靠性、连接管理和性能与资源消耗等方面都存在显著的区别。在选择使用哪种协议时,需要根据具体的应用场景和需求来进行权衡和选择。

8.粘包问题

AI问答

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP 粘包问题是 TCP 编程中常见的一个问题,它主要发生在 TCP 数据传输过程中,由于 TCP 本身是一个“流”协议,而不是一个“包”协议,TCP 不保证发送的数据包边界与接收的数据包边界一致,这就可能导致粘包和拆包问题。

  • 粘包问题简述

粘包 是指发送方发送的多个数据包在接收方被合并成一个数据包接收,或者发送方的一个数据包在接收方被拆分成多个数据包接收。粘包和拆包是 TCP 协议本身不保证消息边界所引起的问题,对于上层应用来说,这可能会导致数据解析错误

  • 粘包问题产生的原因
  1. TCP 缓冲区机制:TCP 传输数据时,会将数据放入缓冲区,然后按照 TCP 窗口大小进行发送。接收方也是将数据放入缓冲区,然后按照 TCP 窗口大小进行接收。如果发送方连续发送数据,且发送的数据小于 TCP 缓冲区的大小,这些数据包就有可能被 TCP 合并为一个大的数据包发送,接收方接收时就可能面临粘包问题。
  2. 网络延迟:在网络条件不佳的情况下,TCP 可能会将多个小的数据包合并成一个大的数据包发送,以减少网络传输的开销,这也可能引发粘包问题。
  3. TCP 的 Nagle 算法:为了减少网络中的小数据包的数量,TCP 使用了一种名为 Nagle 的算法。该算法会延迟小数据包的发送,直到有更大的数据包需要发送或者接收方对前一个数据包的确认到达。这种延迟机制也可能导致粘包。
  • 解决方案【明确边界】
  1. 【定长报文】固定长度消息:发送方和接收方约定每个消息的长度,接收方按照约定的长度来读取数据。
  2. 【使用特殊字符】特殊分隔符:在消息之间添加特定的分隔符(如换行符、回车符等),接收方通过识别分隔符来分割消息。
  3. 【自描述字段+定长报头/特殊字符】消息头部携带长度信息:在每条消息的头部添加表示消息长度的字段,接收方先读取头部信息,然后根据长度信息来读取整个消息。
  4. 应用层协议:设计一套应用层协议,该协议明确规定了消息的格式和解析方式,从而避免粘包和拆包问题。应用层要想获取一个完整的报文,就要对字节流根据某种协议分成一个一个报文。之前的网络版计算器encode和decode就是在解决这个问题!
    通过这些方法,可以在应用层解决 TCP 粘包问题,确保数据的正确传输和解析。成功获取到完整的报文之后,采用序列反序列思想解析数据。【再回头看udp/tcp报头的设计,在底层也是考虑到了这个情况==》读到一个报文,怎么获取报文的数据】

粘包问题中的 “包” , 是指的应用层的数据包。在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段。站在传输层的角度, TCP是一个一个段过来的. 按照序号排好序放在缓冲区中.
站在应用层的角度, 看到的只是一串连续的字节数据.
那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包.应用层取数据时可能取到了1.5个包,这样本次分析数据有影响,之后的也有影响。

那么如何避免粘包问题呢? 归根结底就是一句话, 明确两个包之间的边界.

对于定长的包, 保证每次都按固定大小读取即可; 例如Request结构, 是固定大小的, 那么就从缓冲区从头开始按sizeof(Request)依次读取即可;
对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;
对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序猿自己来定的, 只要保证分隔
符不和正文冲突即可);

思考: 对于UDP协议来说, 是否也存在 “粘包问题” 呢?

对于UDP, 如果还没有上层交付数据, UDP的报文长度仍然在. 同时, UDP是一个一个把数据交付给应用层. 就有很明确的数据边界.
站在应用层的角度, 使用UDP的时候, 要么收到完整的UDP报文, 要么不收. 不会出现"半个"的情况.

9.TCP异常情况

  1. 进程终止: 在OS看来,一个异常进程终止和进程正常退出没有区别,都是把pcb等资源释放。tcp连接和文件是直接相关的,文件的生命周期随进程,tcp连接和进程直接相关!进程终止会释放文件描述符, 仍然可以发送FIN。 和正常关闭没有什么区别。进行正常的四次挥手。【三次链接由用户connect/accept,其余都是OS完成的】
  2. 机器重启: 先进行进程终止。先杀掉所有进程再关机。
  3. 机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行reset. 即使没有写入操作, TCP自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放.另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ断线之后, 也会定期尝试重新连接.

10.再谈文件和socket的关系

在Linux系统中,TCP套接字(TCP socket)和文件/文件描述符(file descriptors)之间存在紧密的关系。这种关系主要源于Linux内核对资源的统一管理方式,其中文件描述符作为访问所有类型I/O资源的通用接口。

文件描述符

文件描述符是一个非负整数,用于标识打开的文件或其他输入/输出资源(如管道、套接字等)。在Linux中,几乎所有的I/O操作都是通过文件描述符来完成的。文件描述符由内核分配,并在打开文件、套接字或其他I/O资源时返回给用户程序。

TCP套接字

TCP套接字是网络通信中的一个端点,用于在两台机器之间实现双向数据流。在Linux中,TCP套接字是通过socket系统调用创建的,这个调用会返回一个文件描述符,该描述符随后被用于对套接字进行读写操作,以及执行其他套接字相关的操作(如监听、连接、绑定等)。

关系

  1. 统一接口:Linux内核通过文件描述符为TCP套接字提供了统一的I/O接口。对套接字的读写操作可以使用与文件操作相同的系统调用(如read、write、select、poll等)。
  2. 资源管理:文件描述符由内核管理,内核通过文件描述符表来跟踪打开的文件和套接字等资源。当进程通过文件描述符对资源进行操作时,内核会查找文件描述符表来确定实际要操作的对象。
  3. 网络I/O:对于TCP套接字而言,文件描述符是网络通信的入口点。通过这个入口点,进程可以发送和接收数据,进行连接管理等操作。
  4. 限制:由于文件描述符是由内核管理的资源,因此它们的数量是有限的。这个限制可以通过/proc/sys/fs/file-max(系统级限制)和ulimit -n(用户级限制)来查看和修改。对于需要大量文件描述符的应用程序(如数据库服务器、Web服务器等),合理管理文件描述符的数量非常重要。

结论

在Linux中,TCP套接字通过文件描述符与内核进行交互,实现了网络通信的底层机制。文件描述符作为统一的I/O接口,不仅简化了系统调用的设计,也提高了资源管理的效率。对于开发涉及网络通信的应用程序来说,深入理解TCP套接字和文件描述符之间的关系是非常重要的。

struct proto_ops{ }

在这里插入图片描述

sk_buff_head — sk_buff — 接收缓冲区接收的是一个个报文 用双链表链接报文链表 — 报文的数据类型即为sk_buff

在这里插入图片描述

sk_buff
在这里插入图片描述

对传输层的理解

协议栈:用特定数据结构表述的协议;和特定协议匹配的方法集

无论是图中的file结构体里的方法集还是socket/udp_sock/tcp_sock里的方法集他们的任务都是接受上层调用把数据传给下层,tcp没有把数据直接干到网络里。

服务器收到多个报文,而报文是要被管理的?如何管理呢?先描述,在组织!

在这里插入图片描述

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

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

相关文章

day09了 加油

浅拷贝 指向同一个地址空间 右边不可取地址 左边一定是到了具体的位置 右值引用std&#xff1a;&#xff1a; move 相信大家默认构造函数都没有问题&#xff0c;所以就不贴例子了 浅拷贝构造函数 只负责复制地址&#xff0c;而不是真的把完整的内存给它 #include <iostre…

Qt——升级系列(Level Seven):事件、文件

目录 Qt事件 事件介绍 事件的处理 按键事件 鼠标事件 定时器 事件分发器 事件过滤器 Qt文件 Qt文件概述 输入输出设备类 文件读写类 文件和目录信息类 Qt事件 事件介绍 事件是应⽤程序内部或者外部产⽣的事情或者动作的统称。在 Qt 中使⽤⼀个对象来表⽰⼀个事件。所有的 Qt …

Linux修炼之路之进程概念,fork函数,进程状态

目录 一&#xff1a;进程概念 二&#xff1a;Linux中的进程概念 三&#xff1a;用getpid(),getppid()获取该进程的PID,PPID 四&#xff1a;用fork()来创建子进程 五&#xff1a;操作系统学科的进程状态 六&#xff1a;Linux中的进程状态 接下来的日子会顺顺利利&#xf…

WordPress网站添加插件和主题时潜在危险分析

WordPress 最初只是一个简单的博客软件&#xff0c;现在据估计为全球前 1000 万个网站中的 30% 提供支持。WordPress受欢迎的因素之一是可以轻松创建插件和主题来扩展它并提供比默认设置更多的功能。 目前&#xff0c;WordPress 网站列出了 56,000 多个插件以及数千个主题。插件…

提升用户体验之requestAnimationFrame实现前端动画

requestAnimationFrame是什么 MDN官方解释 解析这段话&#xff1a; 1、那么浏览器重绘是指什么呢&#xff1f; ——大多数电脑的显示器刷新频率是60Hz&#xff0c;1000ms/6016.66666667ms的时间刷新一次 2、重绘之前调用指定的回调函数更新动画&#xff1f; ——requestAnima…

机器学习辅助的乙醇浓度检测

目录 1.为什么要机器学习 2. 神经网络一般组成 3.BP神经网络工作过程 4.评价指标 5.实操代码 1.为什么要用机器学习 人工分析大量的谐振模式&#xff0c;建立各种WGM的响应与未知目标之间的关系&#xff0c;是一个很大的挑战。机器学习(ML)能够自行识别全谱的全部特征。作为…

Python深度理解系列之【排序算法——冒泡排序】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️木道寻的主页 文章目录 &#x1f525;前言&#x1f680;冒泡排序python实现算法实现图形化算法展示 ⭐️⭐️⭐️总结 &#x1f525;前…

ONLYOFFICE8.1版本桌面编辑器简单测评

ONLYOFFICE官网链接&#xff1a;在线PDF查看器和转换器 | ONLYOFFICE ONLYOFFICE介绍&#xff1a;https://www.onlyoffice.com/zh/office-suite.aspx OnlyOffice 是一款免费且开源的 Office 协作办公套件&#xff0c;支持桌面端和移动端等多平台&#xff0c;由一家领先的 IT 公…

OpenStack开源虚拟化平台(二)

目录 三、对象存储服务Swift&#xff08;一&#xff09;Swift特性&#xff08;二&#xff09;应用场景&#xff08;三&#xff09;Swift主要组件&#xff08;四&#xff09;Swift基本原理&#xff08;五&#xff09;实例分析 四、镜像服务Glance&#xff08;一&#xff09;Glan…

如何在 Java 应用中使用 Jedis 客户端库来实现 Redis 缓存的基本操作

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

图解 Kafka 架构

写在前面 Kafka 是一个可横向扩展&#xff0c;高可靠的实时消息中间件&#xff0c;常用于服务解耦、流量削峰。 好像是 LinkedIn 团队开发的&#xff0c;后面捐赠给apache基金会了。 kafka 总体架构图 Producer&#xff1a;生产者&#xff0c;消息的产生者&#xff0c;是消息的…

不改代码,实现web.config或app.config的连接字符串加密解密

目的&#xff1a;加密字符串&#xff0c;防止明文显示。 好处&#xff1a;不用修改代码&#xff0c;微软自带功能&#xff0c;自动解密。 web.config 参考相关文章&#xff1a; Walkthrough: Encrypting Configuration Information Using Protected Configuration | Microso…

本地通过ollama下载模型,并使用python跑这个本地模型

1&#xff0c;这是ollama地址&#xff0c;下载对应的安装包 https://ollama.com/?viaurlainavpro.com 2&#xff0c;下载完直接安装即可&#xff0c;安装完后&#xff0c;winr打开cmd&#xff0c;出现这个&#xff0c;基本就妥了 3&#xff0c;这里我们需要去下载模型&#x…

笔记:Git学习之应用场景和使用经验

目标&#xff1a;整理Git工具的应用场景和使用经验 一、开发环境 Git是代码版本控制工具&#xff1b;Github是代码托管平台。 工具组合&#xff1a;VSCode Git 需要安装的软件&#xff1a;vscode、Git 其中vscode需要安装的插件&#xff1a;GitLens、Git History 二、应用…

【NLP学习笔记】load_dataset加载数据

除了常见的load_dataset(<hf上的dataset名>)这种方式加载HF上的所有数据外&#xff0c;还有其他custom的选项。 加载HF上部分数据 from datasets import load_dataset c4_subset load_dataset("allenai/c4", data_files"en/c4-train.0000*-of-01024.js…

PowerBi 获取指定时间间隔的日期的方法

获取指定时间间隔的日期&#xff0c;比如我们想得到2024年5月31日后的第三天。 网络上的教程一般是使用DATEADD()函数。 但是这个函数返回的是表。假如我们的需求是不做汇总等计算&#xff0c;只是把它作为一个计算列&#xff0c;或者度量值&#xff0c;那么我更推荐用DATE(&…

webstorm 高效查看不同分支差异 摒弃你的git diff手动操作

背景 每次代码冲突或者版本发生异常时&#xff0c;排查不同版本时就是一个头大的问题&#xff0c;头大的点在于用 vscode 的 git diff 一点点地排查和比较&#xff0c;耗时耗力&#xff0c;版面展不开&#xff0c;commit 差异看不出来&#xff0c;每个页面的代码不同也不能快速…

【Java08】方法(上)

从面向对象的角度来看&#xff0c;Java中的方法是类或对象行为的抽象。但和C不同&#xff0c;Java中”剔除“了C中”残留“的结构化编程。具体地说&#xff0c;Java中的方法必须在类中定义&#xff0c;没有独立存在的函数。 也有人把结构化编程&#xff0c;叫做”面向函数的编程…

Linux基础指令介绍与详解——原理学习

前言&#xff1a;本节内容标题虽然为指令&#xff0c;但是并不只是讲指令&#xff0c; 更多的是和指令相关的一些原理性的东西。 如果友友只想要查一查某个指令的用法&#xff0c; 很抱歉&#xff0c; 本节不是那种带有字典性质的文章。但是如果友友是想要来学习的&#xff0c;…