(翻译 gafferongames) UDP vs. TCP

news/2025/3/20 23:55:10/文章来源:https://www.cnblogs.com/sun-shadow/p/18784240

https://gafferongames.com/post/udp_vs_tcp/

TCP/IP

TCP stands for “transmission control protocol”. IP stands for “internet protocol”. Together they form the backbone for almost everything you do online, from web browsing to IRC to email, it’s all built on top of TCP/IP.

If you have ever used a TCP socket, then you know it’s a reliable connection based protocol. This means you create a connection between two machines, then you exchange data much like you’re writing to a file on one side, and reading from a file on the other.

TCP connections are reliable and ordered. All data you send is guaranteed to arrive at the other side and in the order you wrote it. It’s also a stream protocol, so TCP automatically splits your data into packets and sends them over the network for you.

TCP 代表传输控制协议(Transmission Control Protocol),IP 代表互联网协议(Internet Protocol)。它们共同构成了几乎所有在线活动的基础,无论是网页浏览、IRC 聊天还是电子邮件通信,所有这些都建立在 TCP/IP 之上。

如果你曾使用过 TCP 套接字(socket),那么你就会知道它是一种可靠的、基于连接的协议。这意味着需要在两台计算机之间建立连接,然后才能交换数据,类似于在一端写入文件,而在另一端读取文件。

TCP 连接具有可靠性和有序性。你发送的所有数据都保证能够到达对方,并且按发送顺序到达。此外,TCP 也是一种流协议,它会自动将你的数据拆分成数据包,并通过网络进行传输

 

IP

The simplicity of TCP is in stark contrast to what actually goes on underneath TCP at the IP or “internet protocol” level.

Here there is no concept of connection, packets are simply passed from one computer to the next. You can visualize this process being somewhat like a hand-written note passed from one person to the next across a crowded room, eventually, reaching the person it’s addressed to, but only after passing through many hands.

There is also no guarantee that this note will actually reach the person it is intended for. The sender just passes the note along and hopes for the best, never knowing whether or not the note was received, unless the other person decides to write back!

Of course IP is in reality a little more complicated than this, since no one computer knows the exact sequence of computers to pass the packet along to so that it reaches its destination quickly. Sometimes IP passes along multiple copies of the same packet and these packets make their way to the destination via different paths, causing packets to arrive out of order and in duplicate.

This is because the internet is designed to be self-organizing and self-repairing, able to route around connectivity problems rather than relying on direct connections between computers. It’s actually quite cool if you think about what’s really going on at the low level. You can read all about this in the classic book TCP/IP Illustrated.

TCP 的简单性与其底层的 IP(互联网协议,Internet Protocol)形成了鲜明对比。

在 IP 层,没有“连接”的概念,数据包只是被一台计算机简单地传递到下一台计算机。你可以将这个过程想象成在拥挤的房间里传递一张手写的便条——这张便条最终会到达收件人手中,但在此之前,它需要经过许多人的传递。

此外,这张便条并不能保证一定能送达收件人。发送者只是将便条传出去,然后祈祷它能送到,但除非收件人决定写回,否则发送者永远不会知道便条是否真的到达了目的地。

当然,IP 的实际运作比这个类比要复杂得多。因为没有任何一台计算机确切地知道数据包应该按照怎样的顺序传输,才能最快抵达目的地。有时,IP 会发送同一个数据包的多个副本,而这些数据包可能会通过不同的路径抵达目的地,这就可能导致数据包乱序到达或重复

这是因为互联网的设计是自组织和自修复的,它能够绕过网络连接问题,而不依赖于计算机之间的直接连接。如果你深入思考 IP 层的底层运作,会发现它的机制非常酷!如果你对此感兴趣,可以阅读经典书籍 《TCP/IP 详解》(TCP/IP Illustrated),里面有详细的介绍。

UDP

Instead of treating communications between computers like writing to files, what if we want to send and receive packets directly?

We can do this using UDP.

UDP stands for “user datagram protocol” and it’s another protocol built on top of IP, but unlike TCP, instead of adding lots of features and complexity, UDP is a very thin layer over IP.

With UDP we can send a packet to a destination IP address (eg. 112.140.20.10) and port (say 52423), and it gets passed from computer to computer until it arrives at the destination or is lost along the way.

On the receiver side, we just sit there listening on a specific port (eg. 52423) and when a packet arrives from any computer (remember there are no connections!), we get notified of the address and port of the computer that sent the packet, the size of the packet, and can read the packet data.

Like IP, UDP is an unreliable protocol. In practice however, most packets that are sent will get through, but you’ll usually have around 1-5% packet loss, and occasionally you’ll get periods where no packets get through at all (remember there are lots of computers between you and your destination where things can go wrong…)

There is also no guarantee of ordering of packets with UDP. You could send 5 packets in order 1,2,3,4,5 and they could arrive completely out of order like 3,1,2,5,4. In practice, packets tend to arrive in order most of the time, but you cannot rely on this!

UDP also provides a 16 bit checksum, which in theory is meant to protect you from receiving invalid or truncated data, but you can’t even trust this, since 16 bits is just not enough protection when you are sending UDP packets rapidly over a long period of time. Statistically, you can’t even rely on this checksum and must add your own.

So in short, when you use UDP you’re pretty much on your own!

UDP

如果我们不把计算机之间的通信看作是对文件的读写,而是想要直接发送和接收数据包,该怎么办?

我们可以使用 UDP

UDP 代表 用户数据报协议(User Datagram Protocol),它也是建立在 IP 之上的一种协议。但与 TCP 不同,UDP 没有额外的复杂功能,它只是一个非常轻量级的 IP 协议封装。

使用 UDP,我们可以向目标 IP 地址(例如 112.140.20.10)和端口(例如 52423)发送一个数据包,它会经过多个计算机的传递,最终到达目的地,或者在途中丢失

在接收端,我们只需要监听一个特定的端口(例如 52423),当数据包从任意计算机发送过来时(记住,UDP 没有连接的概念!),我们就会收到通知,得知发送方的 IP 和端口,数据包的大小,并且可以读取数据包内容。

与 IP 类似,UDP 也是一种不可靠的协议。
虽然在实际应用中,大多数数据包都能成功送达,但通常会有 1%~5% 的数据包丢失率,有时甚至会发生短暂的完全丢包(毕竟数据在传输过程中需要经过很多计算机,而这些中间环节可能会出现各种问题……)。

此外,UDP 不保证数据包的顺序。你可能按顺序发送 1,2,3,4,5 这 5 个数据包,但它们可能乱序到达,例如 3,1,2,5,4。在大多数情况下,数据包会按顺序到达,但你不能依赖这一点!

UDP 还提供了一个 16 位校验和,理论上可以防止接收损坏或截断的数据包。然而,在长时间快速发送 UDP 数据包的情况下,16 位校验和的保护能力是不够的,统计上来说,它并不可靠,你必须自己实现额外的校验机制

总而言之,使用 UDP 时,一切都得靠自己!

TCP vs. UDP

We have a decision to make here, do we use TCP sockets or UDP sockets?

Lets look at the properties of each:

TCP:

  • Connection based
  • Guaranteed reliable and ordered
  • Automatically breaks up your data into packets for you
  • Makes sure it doesn't send data too fast for the internet connection to handle (flow control)
  • Easy to use, you just read and write data like its a file

UDP:

  • No concept of connection, you have to code this yourself
  • No guarantee of reliability or ordering of packets, they may arrive out of order, be duplicated, or not arrive at all!
  • You have to manually break your data up into packets and send them
  • You have to make sure you don't send data too fast for your internet connection to handle
  • If a packet is lost, you need to devise some way to detect this, and resend that data if necessary
  • You can't even rely on the UDP checksum so you must add your own

The decision seems pretty clear then, TCP does everything we want and its super easy to use, while UDP is a huge pain in the ass and we have to code everything ourselves from scratch.

So obviously we just use TCP right?

Wrong!

Using TCP is the worst possible mistake you can make when developing a multiplayer game! To understand why, you need to see what TCP is actually doing above IP to make everything look so simple.

我们需要做一个决定:使用 TCP 套接字还是 UDP 套接字?

让我们先看看它们各自的特性:

TCP 的特点:

基于连接(Connection-based)
保证数据可靠且有序(Guaranteed reliable and ordered)
自动拆分数据并打包成数据包(Automatically breaks up your data into packets)
控制数据发送速率,避免网络拥塞(Flow control ensures data isn’t sent too fast for the connection to handle)
易于使用,像读写文件一样操作数据(Easy to use—you just read and write data like a file)

UDP 的特点:

无连接概念,需要自己实现(No concept of connection—you must code this yourself)
不保证数据可靠性或顺序(No guarantee of reliability or ordering—packets may arrive out of order, be duplicated, or not arrive at all!)
需要手动拆分数据并打包成数据包(You must manually break your data into packets and send them)
需要自己控制数据发送速率,防止网络过载(You must ensure you don’t send data too fast for the internet connection)
如果数据包丢失,你需要自己检测并重新发送(If a packet is lost, you must detect this and resend the data if necessary)
UDP 的校验和不可靠,需要自己额外实现校验(You can’t even rely on the UDP checksum—you must add your own!)

 

How TCP really works

TCP and UDP are both built on top of IP, but they are radically different. UDP behaves very much like the IP protocol underneath it, while TCP abstracts everything so it looks like you are reading and writing to a file, hiding all complexities of packets and unreliability from you.

So how does it do this?

Firstly, TCP is a stream protocol, so you just write bytes to a stream, and TCP makes sure that they get across to the other side. Since IP is built on packets, and TCP is built on top of IP, TCP must therefore break your stream of data up into packets. So, some internal TCP code queues up the data you send, then when enough data is pending the queue, it sends a packet to the other machine.

This can be a problem for multiplayer games if you are sending very small packets. What can happen here is that TCP may decide it’s not going to send data until you have buffered up enough data to make a reasonably sized packet to send over the network.

This is a problem because you want your client player input to get to the server as quickly as possible, if it is delayed or “clumped up” like TCP can do with small packets, the client’s user experience of the multiplayer game will be very poor. Game network updates will arrive late and infrequently, instead of on-time and frequently like we want.

TCP has an option to fix this behavior called TCP_NODELAY. This option instructs TCP not to wait around until enough data is queued up, but to flush any data you write to it immediately. This is referred to as disabling Nagle’s algorithm.

Unfortunately, even if you set this option TCP still has serious problems for multiplayer games and it all stems from how TCP handles lost and out of order packets to present you with the “illusion” of a reliable, ordered stream of data.

 

TCP 的真实运作方式

TCP 和 UDP 都是建立在 IP 之上的协议,但它们的运作方式截然不同
UDP 的行为与底层的 IP 协议 非常相似,而 TCP 则隐藏了所有数据包和不可靠性的复杂性,让它看起来就像是在读写一个文件

那么 TCP 是如何做到这一点的呢?

TCP 作为流协议

首先,TCP 是一种流协议(Stream Protocol),你只需要往数据流中写入字节,TCP 就会确保这些数据能够可靠地传输到另一端

但由于 IP 是基于数据包(packet-based) 的,而 TCP 又是建立在 IP 之上,所以 TCP 必须把你的数据流拆分成数据包

这意味着 TCP 会先把你写入的数据排入队列,当累积到足够多的数据后,才会打包成一个数据包并发送给对方计算机。

小数据包延迟问题

如果你在多人游戏中发送非常小的数据包,TCP 可能不会立即发送它们,而是会等到数据足够多时再发送较大的数据包

这会导致问题!

在网络游戏中,你希望客户端的玩家输入能尽快到达服务器,但 TCP 可能会因为“数据不足”而延迟发送,导致数据包被**“堆积”在一起**再一次性发送出去。

结果是:

  • 游戏数据更新变得缓慢和不频繁
  • 玩家的输入反应延迟变高
  • 多人游戏体验变得极差

TCP_NODELAY 选项

TCP 有一个选项可以修复这个问题,它叫做 TCP_NODELAY

当这个选项开启时,TCP 不会再等待数据堆积,而是立即发送你写入的数据。这个过程被称为 禁用 Nagle 算法(Nagle’s Algorithm)

即使你启用了 TCP_NODELAYTCP 仍然不适用于多人游戏

TCP 处理丢包和乱序的方式

TCP 真正的问题在于它如何处理丢失或乱序的数据包,以向你提供“可靠、有序的数据流的假象”

这个机制,才是 TCP 在多人游戏中致命的缺陷! 🚨

在接下来的部分,我们将深入探讨 TCP 是如何处理丢包的,以及为什么这会导致严重的游戏延迟问题

How TCP implements reliability

Fundamentally TCP breaks down a stream of data into packets, sends these packets over unreliable IP, then takes the packets received on the other side and reconstructs the stream.

But what happens when a packet is lost?

What happens when packets arrive out of order or are duplicated?

Without going too much into the details of how TCP works because its super-complicated (please refer to TCP/IP Illustrated) in essence TCP sends out a packet, waits a while until it detects that packet was lost because it didn’t receive an ack (or acknowledgement), then resends the lost packet to the other machine. Duplicate packets are discarded on the receiver side, and out of order packets are resequenced so everything is reliable and in order.

The problem is that if we were to send our time critical game data over TCP, whenever a packet is dropped it has to stop and wait for that data to be resent. Yes, even if more recent data arrives, that new data gets put in a queue, and you cannot access it until that lost packet has been retransmitted. How long does it take to resend the packet?

Well, it’s going to take at least round trip latency for TCP to work out that data needs to be resent, but commonly it takes 2*RTT, and another one way trip from the sender to the receiver for the resent packet to get there. So if you have a 125ms ping, you’ll be waiting roughly 1/5th of a second for the packet data to be resent at best, and in worst case conditions you could be waiting up to half a second or more (consider what happens if the attempt to resend the packet fails to get through?). What happens if TCP decides the packet loss indicates network congestion and it backs off? Yes it actually does this. Fun times!

TCP 实现可靠性

从根本上讲,TCP 将数据流分解为数据包,通过不可靠的 IP 发送这些数据包,然后在接收端接收这些数据包并重新构建数据流。

但如果数据包丢失了,怎么办?

如果数据包乱序或重复,怎么办?

简而言之,TCP 发送一个数据包,等待一段时间来检测该数据包是否丢失,因为没有收到确认(acknowledgement)。如果丢失,它会重新发送该数据包到另一台机器。接收端会丢弃重复的数据包,并重新排序乱序的数据包,因此一切都是可靠且有序的。

问题是,如果我们将时间敏感的游戏数据通过 TCP 发送,一旦数据包丢失,它就必须停止并等待该数据包的重新发送。是的,即使更新的数据包到达,新的数据包也会被放入队列中,直到丢失的数据包被重新传输。重新发送数据包需要多长时间?

实际上,TCP 必须至少等待一个往返延迟(RTT)来确定数据包丢失,然后通常需要 2*RTT 的时间,再加上重新发送的数据包从发送端到接收端的单程时间。因此,如果你的 ping 是 125ms,那么你至少需要等待约五分之一秒来重新发送数据包,在最坏的情况下,可能需要等待半秒甚至更长时间(考虑到如果重新发送的数据包未成功发送会发生什么?)。如果 TCP 认为数据包丢失是由于网络拥塞,它还会进行退避。是的,它确实会这样做。挺有趣的吧!

Never use TCP for time critical data

The problem with using TCP for realtime games like FPS is that unlike web browsers, or email or most other applications, these multiplayer games have a real time requirement on packet delivery.

What this means is that for many parts of a game, for example player input and character positions, it really doesn’t matter what happened a second ago, the game only cares about the most recent data.

TCP was simply not designed with this in mind.

Consider a very simple example of a multiplayer game, some sort of action game like a shooter. You want to network this in a very simple way. Every frame you send the input from the client to the server (eg. keypresses, mouse input controller input), and each frame the server processes the input from each player, updates the simulation, then sends the current position of game objects back to the client for rendering.

So in our simple multiplayer game, whenever a packet is lost, everything has to stop and wait for that packet to be resent. On the client game objects stop receiving updates so they appear to be standing still, and on the server input stops getting through from the client, so the players cannot move or shoot. When the resent packet finally arrives, you receive this stale, out of date information that you don’t even care about! Plus, there are packets backed up in queue waiting for the resend which arrive at same time, so you have to process all of these packets in one frame. Everything is clumped up!

Unfortunately, there is nothing you can do to fix this behavior, it’s just the fundamental nature of TCP. This is just what it takes to make the unreliable, packet-based internet look like a reliable-ordered stream.

Thing is we don’t want a reliable ordered stream.

We want our data to get as quickly as possible from client to server without having to wait for lost data to be resent.

This is why you should never use TCP when networking time-critical data!

永远不要在即时数据中使用 TCP

使用 TCP 进行实时游戏(例如 FPS)的一个问题是,与网页浏览器、电子邮件或大多数其他应用程序不同,这些多人游戏对数据包传输有实时要求。

这意味着,对于游戏中的许多部分,例如玩家输入和角色位置,实际上并不关心一秒钟前发生了什么,游戏只关心最新的数据。

TCP 根本没有考虑到这一点。

考虑一个非常简单的多人游戏示例,比如射击类游戏。你希望以非常简单的方式进行网络连接。每一帧,你都将客户端的输入(例如按键、鼠标输入、控制器输入)发送到服务器,然后每一帧服务器处理每个玩家的输入,更新模拟,并将当前游戏对象的位置返回给客户端进行渲染。

所以,在我们的简单多人游戏中,每当一个数据包丢失时,所有的操作必须停止,等待该数据包重新发送。在客户端,游戏对象停止接收更新,因此它们看起来像是静止的;在服务器端,客户端的输入无法传输,所以玩家无法移动或射击。当重新发送的数据包最终到达时,你收到的是陈旧的、过时的信息,甚至你并不关心这些数据!此外,排队等待重新发送的其他数据包也会同时到达,这意味着你必须在同一帧中处理所有这些数据包。一切都堆积在一起!

不幸的是,你无法修复这种行为,这是 TCP 的基本性质。为了让不可靠的基于数据包的互联网看起来像是可靠且有序的流,这就是必须付出的代价。

问题是,我们并不需要一个可靠的、有序的流。

我们希望我们的数据尽可能快速地从客户端传输到服务器,而无需等待丢失的数据包重新发送。

这就是为什么你永远不要在即时数据中使用 TCP!

Wait? Why can’t I use both UDP and TCP?

For realtime game data like player input and state, only the most recent data is relevant, but for other types of data, say perhaps a sequence of commands sent from one machine to another, reliability and ordering can be very important.

The temptation then is to use UDP for player input and state, and TCP for the reliable ordered data. If you’re sharp you’ve probably even worked out that you may have multiple “streams” of reliable ordered commands, maybe one about level loading, and another about AI. Perhaps you think to yourself, “Well, I’d really not want AI commands to stall out if a packet is lost containing a level loading command - they are completely unrelated!”. You are right, so you may be tempted to create one TCP socket for each stream of commands.

On the surface, this seems like a great idea. The problem is that since TCP and UDP are both built on top of IP, the underlying packets sent by each protocol will affect each other. Exactly how they affect each other is quite complicated and relates to how TCP performs reliability and flow control, but fundamentally you should remember that TCP tends to induce packet loss in UDP packets. For more information, read this paper on the subject.

Also, it’s pretty complicated to mix UDP and TCP. If you mix UDP and TCP you lose a certain amount of control. Maybe you can implement reliability in a more efficient way that TCP does, better suited to your needs? Even if you need reliable-ordered data, it’s possible, provided that data is small relative to the available bandwidth to get that data across faster and more reliably that it would if you sent it over TCP. Plus, if you have to do NAT to enable home internet connections to talk to each other, having to do this NAT once for UDP and once for TCP (not even sure if this is possible…) is kind of painful.

等等?为什么不能同时使用 UDP 和 TCP?

对于像玩家输入和状态这样的实时游戏数据,只有最新的数据才是相关的,但对于其他类型的数据,例如从一台机器发送到另一台机器的命令序列,可靠性和顺序可能非常重要。

于是,诱惑是使用 UDP 来传输玩家输入和状态,而使用 TCP 来处理可靠的、有序的数据。如果你足够聪明,可能已经意识到你可能会有多个“流”来传输可靠的、有序的命令,也许一个用于关卡加载,另一个用于 AI。也许你会想,“嗯,我真的不想因为丢失了包含关卡加载命令的数据包而导致 AI 命令卡住——它们是完全无关的!”你是对的,所以你可能会想为每个命令流创建一个 TCP 套接字。

从表面上看,这似乎是一个不错的主意。问题在于,由于 TCP 和 UDP 都是建立在 IP 协议之上的,它们各自发送的底层数据包会互相影响。它们如何相互影响是相当复杂的,涉及到 TCP 如何执行可靠性和流量控制,但从根本上讲,你应该记住,TCP 通常会导致 UDP 数据包丢失。关于这个问题的更多信息,请阅读这篇论文。

此外,混合使用 UDP 和 TCP 也相当复杂。如果你混合使用 UDP 和 TCP,你会失去一定程度的控制。也许你可以实现比 TCP 更高效的可靠性机制,更适合你的需求?即使你需要可靠且有序的数据,这也是可能的,只要该数据相对于可用带宽较小,你就能比通过 TCP 发送时更快且更可靠地传输这些数据。此外,如果你需要进行 NAT(网络地址转换)以使家庭互联网连接能够相互通信,那么对于 UDP 和 TCP 各进行一次 NAT(甚至不确定这是否可能)会变得非常麻烦

Conclusion

My recommendation is not only that you use UDP, but that you only use UDP for your game protocol. Don’t mix TCP and UDP! Instead, learn how to implement the specific features of TCP that you need inside your own custom UDP based protocol.

Of course, it is no problem to use HTTP to talk to some RESTful services while your game is running. I’m not saying you can’t do that. A few TCP connections running while your game is running isn’t going to bring everything down. The point is, don’t split your game protocol across UDP and TCP. Keep your game protocol running over UDP so you are fully in control of the data you send and receive and how reliability, ordering and congestion avoidance are implemented.

The rest of this article series show you how to do this, from creating your own virtual connection on top of UDP, to creating your own reliability, flow control and congestion avoidance.

结论

我的建议不仅是使用 UDP,而且仅使用 UDP 来构建你的游戏协议。不要混合使用 TCP 和 UDP!相反,学习如何在你自己的自定义 UDP 协议中实现 TCP 所需要的特性。

当然,在你的游戏运行时,使用 HTTP 与一些 RESTful 服务进行通信并没有问题。我并不是说你不能这样做。游戏运行时进行几条 TCP 连接不会让一切崩溃。关键是,不要将你的游戏协议拆分为 UDP 和 TCP 两部分。保持你的游戏协议通过 UDP 运行,这样你就能完全控制你发送和接收的数据,以及如何实现可靠性、顺序和拥塞避免。

本系列文章的其余部分将向你展示如何做到这一点,从在 UDP 上创建你自己的虚拟连接,到创建你自己的可靠性、流量控制和拥塞避免机制。

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GKI改造原则、机制和方法

Google在android11-5.4分支上开始要求所有下游厂商使用Generic Kernel Image(GKI),需要将SoC和device相关的代码从核心内核剥离到可加载模块中(下文称之为GKI改造),从而解决内核碎片化问题。GKI为内核模块提供了稳定的内核模块接口(KMI),模块和内核可以独立更新。本文…

鸿蒙特效教程07-九宫格幸运抽奖

鸿蒙特效教程07-九宫格幸运抽奖在移动应用中,抽奖功能是一种常见且受欢迎的交互方式,能够有效提升用户粘性。本教程将带领大家从零开始,逐步实现一个九宫格抽奖效果,适合HarmonyOS开发的初学者阅读。最终效果预览 我们将实现一个经典的九宫格抽奖界面,包含以下核心功能:3…

Ollama系列05:Ollama API 使用指南

本文是Ollama系列教程的第5篇,在前面的4篇内容中,给大家分享了如何再本地通过Ollama运行DeepSeek等大模型,演示了chatbox、CherryStudio等UI界面中集成Ollama的服务,并介绍了如何通过cherryStudio构建私有知识库。 在今天的分享中,我将分享如何通过API来调用ollama服务,通…

前端HTML+CSS+JS速成笔记

HTML 超文本标记语言。 单标签与双标签的区别 单标签用于没有内容的元素,双标签用于有内容的元素。 HTML文件结构 告诉浏览器这还是一个 Html 文件: <!DOCTYPE html>Html文件的范围: <html>...</html>Html 文件的头: <head>...</head>实际显…

12. ADC

一、ADC简介生活中接触到的大多数信息是醉着时间连续变化的物理量,如声音、温度、压力等。表达这些信息的电信号,称为 模拟信号(Analog Signal)。为了方便存储、处理,在计算机系统中,都是数字 0 和 1 信号,将模拟信号(连续信号)转换为数字信号(离散信号)的器件就叫模…

【刷题笔记】力扣 40. 组合总和 II——回溯算法中的去重

40. 组合总和 II 中等 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 示例 1: 输入: candidates = [10,1,2,7,6,1,…

Spring AI 搭建AI原生应用 [clone]

作者 | 文心智能体平台导读 本文以快速开发一个 AI 原生应用为目的,介绍了 Spring AI 的包括对话模型、提示词模板、Function Calling、结构化输出、图片生成、向量化、向量数据库等全部核心功能,并介绍了检索增强生成的技术。依赖 Spring AI 提供的功能,我们可以轻松开发出…

mybatis逆向工程插件配置(mybatis-generator-maven-plugin)

MyBatis逆向工程是一种自动化工具,可以将数据库表结构转换为MyBatis的Mapper XML文件和相应的Java接口和对应的实体类。 1.生成maven项目 2.pom.xml文件中导入逆向工程插件相关配置<!--mybatis逆向工程--><build><plugins><!--其中的一个插件,逆向工程插…

Day01-Java项目学习

Day01 后端环境搭建 lombok插件 通过lombok插件。@Data 可以使用@Data、@Getter、@Setter等注解的形式,来对一个Java Bean(具有Getter,Setter方法的对象)实现快速的初始化。 @Slf4j 可以以注解的形式,自动化日志变量,通过添加@Slf4j(simple logging Facade for Java)生成…

20241105 实验一 《Python程序设计》

课程:《Python程序设计》 班级: 2411 姓名: 王梓墨 学号:20241105 实验教师:王志强 实验日期:2025年3月12日 必修/选修: 公选课 一.实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能;(编写书中的程序,并进行调试分析) 3.编写程序,练习变量和类型、字…

英语四级备考第二天

第二天 今天是开始英语备考的第二天,当迈出第二步的时候,就意味着正走在通过考试的路上。到时当你以425分毋庸置疑地通过考试时,过去的90天都不曾虚度。 单词 今天新学的单词加上昨天应复习的单词,在50~60个之间。阅读 今天的阅读还是用扇贝单词推荐的包含学习的单词的文章…