当前位置: 首页 > news >正文

Linux的Socket开发概述

套接字(socket)是 Linux 下的一种进程间通信机制(socket IPC),在前面的内容中已经给大家提到过,使用 socket IPC 可以使得在不同主机上的应用程序之间进行通信(网络通信),当然也可以是同一台主机上的不同应用程序。socket IPC 通常使用客户端<--->服务器这种模式完成通信,多个客户端可以同时连接到服务器中,与服务器之间完成数据交互。

内核向应用层提供了 socket 接口,对于应用程序开发人员来说,我们只需要调用 socket 接口开发自己的应用程序即可!socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口。在设计模式中,socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议隐藏在 socket 接口后面,对用户来说,一组简单的接口就是全部,让 socket 去组织数据,以符合指定的协议。所以,我们无需深入的去理解 tcp/udp 等各种复杂的 TCP/IP 协议,socket 已经为我们封装好了,我们只需要遵循 socket 的规定去编程,写出的程序自然遵循 tcp/udp 标准的。

当前网络中的主流程序设计都是使用 socket 进行编程的,因为它简单易用,它还是一个标准(BSD socket),能在不同平台很方便移植,比如你的一个应用程序是基于 socket 接口编写的,那么它可以移植到任何实现 BSD socket 标准的平台,譬如 LwIP,它兼容 BSD Socket;又譬如 Windows,它也实现了一套基于socket 的套接字接口,更甚至在国产操作系统中,如 RT-Thread,它也实现了 BSD socket 标准的 socket 接口。

BSD套接字是最早在1983年随着BSD操作系统发布的套接字接口的名称。后来,这个接口被整合到了POSIX规范中,并增加了一些更详细的操作规范。除了术语不同以外,可以认为没有任何区别。BSD套接字涵盖了随着BSD操作系统发布的API,而POSIX标准适用于任何希望符合POSIX的操作系统。

可参考:

具体了解该套接字,可参考:

伯克利套接字(BSD Socket)-CSDN博客

建立连接相关API 

socket()函数

socket()函数原型如下所示:

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

socket()函数类似于 open()函数,它用于创建一个网络通信端点(打开一个网络通信),如果成功则返回一个网络文件描述符,通常把这个文件描述符称为 socket 描述符(socket descriptor),这个 socket 描述符跟文件描述符一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

该函数包括 3 个参数,如下所示:

domain

参数 domain 用于指定一个通信域;这将选择将用于通信的协议族。可选的协议族如下表所示:

对于 TCP/IP 协议来说,通常选择 AF_INET 就可以了,当然如果你的 IP 协议的版本支持 IPv6,那么可以选择 AF_INET6。

type

参数 type 指定套接字的类型,当前支持的类型有:

protocol

即协议类别,表示为给定的通信域和套接字类型选择默认协议,一般设置为0即可,因为该函数会通过前两个参数自动推导出第三个参数的协议类别。

调用 socket()与调用 open()函数很类似,调用成功情况下,均会返回用于文件 I/O 的文件描述符,只不过对于 socket()来说,其返回的文件描述符一般称为 socket 描述符。当不再需要该文件描述符时,可调用close()函数来关闭套接字,释放相应的资源。

如果 socket()函数调用失败,则会返回-1,并且会设置 errno 变量以指示错误类型。

使用示例

int socket_fd = socket(AF_INET, SOCK_STREAM, 0);//打开套接字
if (0 > socket_fd) {perror("socket error");exit(-1);
}
......
......
close(socket_fd); //关闭套接字

注意,初始时,客户端和服务器都需要调用socket,来指定使用的协议族和socket类型。

bind()函数

bind()函数原型如下所示:

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

bind()函数用于将一个 IP 地址和端口号与一个套接字进行绑定,对于客户端来说,它与服务器进行通信,首先需要知道服务器的 IP 地址以及对应的端口号,通常服务器的 IP 地址以及端口号都是众所周知的。

调用 bind()函数将参数 sockfd 指定的套接字与一个地址 addr 进行绑定,成功返回 0,失败情况下返回-1,并设置 errno 以提示错误原因。

参数 addr 是一个指针,指向一个 struct sockaddr 类型变量,如下所示:

struct sockaddr {sa_family_t sa_family;char sa_data[14];
}

第二个成员 sa_data 是一个 char 类型数组,一共 14 个字节,在这 14 个字节中就包括了 IP 地址、端口号等信息,这个结构对用户并不友好,它把这些信息都封装在了 sa_data 数组中,这样使得用户不方便对sa_data 数组进行赋值。事实上,这是一个通用的 socket 地址结构体。

一般我们在使用的时候都会使用 struct sockaddr_in 结构体,sockaddr_in 和 sockaddr 是并列的结构(占用的空间是一样的),指向 sockaddr_in 的结构体的指针也可以指向 sockadd 的结构体,并代替它,而且sockaddr_in 结构对用户将更加友好,在使用的时候进行类型转换就可以了。该结构体内容如下所示:

struct sockaddr_in {sa_family_t sin_family;/* 协议族 */in_port_t sin_port;/* 端口号 */struct in_addr sin_addr;/* IP 地址 */unsigned char sin_zero[8];
};

这个结构体的第一个字段是与 sockaddr 结构体是一致的,而剩下的字段就是 sa_data 数组连续的 14 字节信息里面的内容,只不过从新定义了成员变量而已,sin_port 字段是我们需要填写的端口号信息,sin_addr字段是我们需要填写的 IP 地址信息,剩下 sin_zero 区域的 8 字节保留未用。

bind函数的最后一个参数 addrlen 指定了 addr 所指向的结构体对应的字节长度。

使用示例

struct sockaddr_in socket_addr;
memset(&socket_addr, 0x0, sizeof(socket_addr)); //清零
//填充变量
socket_addr.sin_family = AF_INET;
socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
socket_addr.sin_port = htons(5555);
//将地址与套接字进行关联、绑定
bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(socket_addr));

注意,代码中的 htons 和 htonl 并不是函数,只是一个宏定义,主要的作用在于为了避免大小端的问题,需要这些宏需要在我们的应用程序代码中包含头文件<netinet/in.h>。

说明:

ip用来确定一台设备,端口号用来确定一个进程。

bind函数是在服务端使用,并且绑定的是服务器本身的ip和端口号。

为啥不是绑定对方的ip和端口?比如客户端绑定服务器的,服务器绑定客户端的,可根据使用情况来看,只有服务端需要用bind,并且绑定的是自己的ip和端口,好像客户端的ip和端口不用显式绑定,为啥?

所以,为什么TCP服务端需要调用bind函数而客户端通常不需要呢?

bind是为了将当前的socket(可以理解成网络连接实例)绑定到了服务端的ip和端口上,然后服务端就可以实时监听有没有客户端连接到了这个socket上,也就是说,一旦绑定的这个ip和端口有动静,服务端就可以响应了。

客户端上线是主动向服务器发出请求的,因为服务器已经绑定了IP和端口,所以客户端上线的就向这个IP和端口发出请求,这时因为客户开始发数据了(发上线请求),操作系统就给客户端分配一个随机端口,这个端口和客户端的IP会随着上线请求一起发给服务器。

服务器收到上线请求后就可以从中获发此请求的客户的IP(源ip字段)和端口,接下来服务器就可以利用获的IP和端口给客户端回应消息了。

总之一句话:客户端是主动连接(Connect),而服务器是等待接受连接(Accept)

注意:一旦建立了连接,客户端 和 服务器端 均可以发送(Send)或者接收(Receive)数据。

更多参考:

为什么TCP服务端需要调用bind函数而客户端通常不需要呢?_tcp bind-CSDN博客

Tips:bind()函数并不是总是需要调用的,只有用户进程想与一个具体的 IP 地址或端口号相关联的时候才需要调用这个函数。如果用户进程没有这个必要,那么程序可以依赖内核的自动的选址机制来完成自动地址选择,通常在客户端应用程序中会这样做。

难怪客户端可以使用动态IP地址,原来是客户端可以让操作系统来自动获取ip和端口。

tcp服务端必须有bind, 客户端通常不用bind,  当然如果你够无聊, 那也可以用一下bind。在这里, 我要说一下了: 客户端用bind的程序很容易出问题, 你想想啊, 操作系统指定的不会冲突的随机端口难道不比你自己指定的容易冲突的固定端口好?在很多场景下, 我们要在一个pc上开启多个客户端进程, 如果指定固定端口,必然会造成端口冲突,影响通信!所以,我们就不要费力不讨好了,客户端就不要指定端口了,让操作系统来搞。

listen()函数

listen()函数只能在服务器进程中使用,让服务器进程进入监听状态,等待客户端的连接请求,listen()函数在一般在 bind()函数之后调用,在 accept()函数之前调用,它的函数原型是:

int listen(int sockfd, int backlog);

无法在一个已经连接的套接字(即已经成功执行 connect()的套接字或由 accept()调用返回的套接字)上执行 listen()。

参数 backlog 用来描述 sockfd 的等待连接队列能够达到的最大值。在服务器进程正处理客户端连接请求的时候,可能还存在其它的客户端请求建立连接,因为 TCP 连接是一个过程,由于同时尝试连接的用户过多,使得服务器进程无法快速地完成所有的连接请求,那怎么办呢?直接丢掉其他客户端的连接肯定不是一个很好的解决方法。因此内核会在自己的进程空间里维护一个队列,这些连接请求就会被放入一个队列中,服务器进程会按照先来后到的顺序去处理这些连接请求,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限,这个 backlog 参数告诉内核使用这个数值作为队列的上限。而当一个客户端的连接请求到达并且该队列为满时,客户端可能会收到一个表示连接失败的错误,本次请求会被丢弃不作处理。 一般设置为5、10。

accept()函数

服务器调用 listen()函数之后,就会进入到监听状态,等待客户端的连接请求,使用 accept()函数获取客户端的连接请求并建立连接。函数原型如下所示:

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

为了能够正常让客户端能正常连接到服务器,服务器必须遵循以下处理流程:

①、调用 socket()函数打开套接字;

②、调用 bind()函数将套接字与一个端口号以及 IP 地址进行绑定;

③、调用 listen()函数让服务器进程进入监听状态,监听客户端的连接请求;

④、调用 accept()函数处理到来的连接请求。

accept()函数通常只用于服务器应用程序中,如果调用 accept()函数时,并没有客户端请求连接(等待连接队列中也没有等待连接的请求),此时 accept()会进入阻塞状态,直到有客户端连接请求到达为止。当有客户端连接请求到达时,accept()函数与远程客户端之间建立连接,accept()函数返回一个新的套接字。这个套接字与 socket()函数返回的套接字并不同,socket()函数返回的是服务器的套接字(以服务器为例),而accept()函数返回的套接字连接到调用 connect()的客户端,服务器通过该套接字与客户端进行数据交互,譬如向客户端发送数据、或从客户端接收数据。

所以,理解 accept()函数的关键点在于它会创建一个新的套接字,其实这个新的套接字就是与执行connect()(客户端调用 connect()向服务器发起连接请求)的客户端之间建立了连接,这个套接字代表了服务器与客户端的一个连接。如果 accept()函数执行出错,将会返回-1,并会设置 errno 以指示错误原因。

参数 addr 是一个传出参数,参数 addr 用来返回已连接的客户端的 IP 地址与端口号等这些信息。参数addrlen 应设置为 addr 所指向的对象的字节长度,如果我们对客户端的 IP 地址与端口号这些信息不感兴趣,可以把 arrd 和 addrlen 均置为空指针 NULL。

connect()函数

connect()函数原型如下所示:

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

该函数用于客户端应用程序中,客户端调用 connect()函数将套接字 sockfd 与远程服务器进行连接,参数 addr 指定了待连接的服务器的 IP 地址以及端口号等信息,参数 addrlen 指定了 addr 指向的 struct sockaddr对象的字节大小。

客户端通过 connect()函数请求与服务器建立连接,对于 TCP 连接来说,调用该函数将发生 TCP 连接的握手过程,并最终建立一个 TCP 连接,而对于 UDP 协议来说,调用这个函数只是在 sockfd 中记录服务器IP 地址与端口号,而不发送任何数据。

函数调用成功则返回 0,失败返回-1,并设置 errno 以指示错误原因。

数据读写相关API

一旦客户端与服务器建立好连接之后,我们就可以通过套接字描述符来收发数据了(对于客户端使用socket()返回的套接字描述符,而对于服务器来说,需要使用 accept()返回的套接字描述符),这与我们读写普通文件是差不多的操作,譬如可以调用 read()或 recv()函数读取网络数据,调用 write()或 send()函数发送数据。

read()函数

read()函数大家都很熟悉了,通过 read()函数从一个文件描述符中读取指定字节大小的数据并放入到指定的缓冲区中,read()调用成功将返回读取到的字节数,此返回值受文件剩余字节数限制,当返回值小于指定的字节数时并不意味着错误;这可能是因为当前可读取的字节数小于指定的字节数(比如已经接近文件结尾,或者正在从管道或者终端读取数据,或者 read()函数被信号中断等),出错返回-1 并设置 errno,如果在调 read 之前已到达文件末尾,则这次 read 返回 0。

套接字描述符也是文件描述符,所以使用 read()函数读取网络数据时,read()函数的参数 fd 就是对应的套接字描述符。

recv()函数

recv()函数原型如下所示:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

不论是客户端还是服务器都可以通过 revc()函数读取网络数据,它与 read()函数的功能是相似的。参数sockfd 指定套接字描述符,参数 buf 指向了一个数据接收缓冲区,参数 len 指定了读取数据的字节大小,参数 flags 可以指定一些标志用于控制如何接收数据。

函数 recv()与 read()很相似,但是 recv()可以通过指定 flags 标志来控制如何接收数据,通常一般我们将 flags 参数设置为 0,当然,你可以根据自己的需求设置该参数。

write()函数

通过 write()函数可以向套接字描述符中写入数据,函数调用成功返回写入的字节数,失败返回-1,并设置 errno 变量。

send()函数

函数原型如下所示:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

send 和 write 很相似,但是 send 可以通过参数 flags 指定一些标志,来改变处理传输数据的方式。

即使 send()成功返回,也并不表示连接的另一端的进程就一定接收了数据,我们所能保证的只是当 send成功返回时,数据已经被无错误的发送到网络驱动程序上。

close()函数

当不再需要套接字描述符时,可调用 close()函数来关闭套接字,释放相应的资源。

参考示例

综合实践之TCP参考:

TCP(TCP客户端、服务器如何通信)_tcp客户端和服务器-CSDN博客

综合实践之UDP参考:

UDP编程流程(UDP客户端、服务器互发消息流程)_udp网络编程-CSDN博客

注意:在TCP连接中,服务器通常处于被动状态,等待客户端的连接请求。而客户端则处于主动状态,负责发起连接请求。一旦连接建立成功,双方就可以进行数据传输。  

TCP和UDP通信过程对比图如下:

更多待补充。

更多参考:

【网络】网络编程_编写网络程序-CSDN博客

RPC

什么是rpc?

进程间通信-浅谈RPC- 最小原型_进程间rpc-CSDN博客

RPC框架:从原理到选型,一文带你搞懂RPC-CSDN博客

深入理解RPC:从原理到实战_深入理解rpc框架原理与实现 pdf-CSDN博客

RPC、Http、TCP/IP、Socket之间的关系及定义_socket rpc-CSDN博客

有了 HTTP 协议,为什么还要 RPC 协议,两者有什么区别?-腾讯云开发者社区-腾讯云 (tencent.com)

RPC核心原理和实战 —— 基础篇 | Focus-1

暂时了解下吧,后续有实际应用场景时再补充。

InternetSocket和UnixSocket 

以前一直以为socket只是两个网络主机之间的进程通信,原来socket也可以用在一个主机上的两个进程之间的通信。

参考:

Internet socket和Unix socket_socket类型 internet unix-CSDN博客

unix socket通信,UNIX Domain SOCKET 是在Socket架构上发展起来的用于同一台主机的进程间通信(IPC)。它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序列号应答等。只是将应用层数据从一个进程拷贝到另一个进程。

使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。

UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

无论是internet socket还是unix socket,服务端和客户端创建socket并进行通信的步骤都是一致的

服务端: socket -> bind -> listen -> accept -> write/send或read/recv -> close

客户端: socket -> connect -> write/send或read/recv -> close

并且每一步骤调用的函数也都是同样的函数,不同点主要在于

  1. socket函数domain字段的值不同,internet socket值为AF_INET,unix socket值为AF_UNIX
  2. socket函数的type参数的值都是SOCK_STREAM和SOCK_DGRAM,但是对于unix socket通信来说,由于是进程间的通信,这两种类型提供的服务都是可靠的
  3. bind函数中,internet socket传入的结构体是sockaddr_in,并且会绑定ip地址和端口号,unix socket传入的结构体是sockaddr_un,会绑定一个用于进程间通信的文件,但是都是需要进行强制转换的
  4. accept函数中,internet socket需要传入sockaddr_in结构体来保存发出请求的客户端的地址,但是在unix socket中,这一项为NULL,在进程通信中,在服务端上无法确定出来这个客户端进程是哪一个

后边的收发数据的调用过程都是一样的,总体来看,两种socket通信的步骤是一致的,但是用于是不一样的,一个是用于网络中两个主机之间的通信,另一个则是一个主机中两个进程之间的通信,这种一致性我觉得可能是因为linux系统中的一切皆文件的思想,无论是进程间通信或者是主机间通信,通过socket函数就能返回一个文件描述符,这个文件描述符的背后可能是用于网络传输的网络连接,或者是进程间的通信,但是对于编程者而言就是用于输入输出的一个文件描述符,这样进程间的通信和主机间的通信都被抽象成了对一个文件的输入输出操作,所以才造成了internet socket和unix socket通信的这种一致性;在细节方面,也正是因为有bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)函数,它提供了一个同一的结构体,在不同类型的socket编程时可以让sockaddr_un和sockaddr_in结构体强制类型转换,所以能够让编写不同类型的socket程序的时候可以调用同样的接口,才造成了在编程时候的这种一致性。

注意,UNIX计算机配置了一个只包含它自身的回路(loopback)网络,网络中只有一台计算机localhost,它有一个标准的IP地址127.0.0.1。

更多参考:

Linux的套接字——进程间通信的另一种方法_进程内部可以通过套接字进行通信吗-CSDN博客

套接字是一种通信机制,通过使用套接字接口,一台机器上的进程可以和另一台机器上的进程进行网络通信,同一台机器之间的进程也可以互相通信。

相关文章:

Linux的Socket开发概述

套接字&#xff08;socket&#xff09;是 Linux 下的一种进程间通信机制&#xff08;socket IPC&#xff09;&#xff0c;在前面的内容中已经给大家提到过&#xff0c;使用 socket IPC 可以使得在不同主机上的应用程序之间进行通信&#xff08;网络通信&#xff09;&#xff0c…...

LLM调优,大模型怎么学

背景 LLM Transparency Tool 是一个用于深入分析和理解大型语言模型&#xff08;LLM&#xff09;工作原理的工具&#xff0c;旨在增加这些复杂系统的透明度。它提供了一个交互式界面&#xff0c;用户可以通过它观察、分析模型对特定输入&#xff08;prompts&#xff09;的反应…...

XLSX + LuckySheet + LuckyExcel实现前端的excel预览

文章目录 功能简介简单代码实现效果参考 功能简介 通过LuckyExcel的transformExcelToLucky方法&#xff0c; 我们可以把一个文件直接转成LuckySheet需要的json字符串&#xff0c; 之后我们就可以用LuckySheet预览excelLuckyExcel只能解析xlsx格式的excel文件&#xff0c;因此对…...

在Ubuntu上创建和启用交换文件的简单步骤

文章目录 为什么使用交换文件&#xff1f;步骤 1&#xff1a;创建交换文件步骤 2&#xff1a;设置正确的权限步骤 3&#xff1a;将文件格式化为交换空间步骤 4&#xff1a;启用交换文件步骤 5&#xff1a;验证交换文件步骤 6&#xff1a;永久启用交换文件步骤 7&#xff1a;调整…...

Java [ 基础 ] HashMap详解 ✨

目录 ✨探索Java基础 HashMap详解✨ 总述 主体 1. HashMap的基本概念 2. HashMap的工作原理 3. HashMap的常用操作 4. HashMap的优缺点 总结 常见面试题 常见面试题解答 1. HashMap的底层实现原理是什么&#xff1f; 2. 如何解决HashMap中的哈希冲突&#xff1f;…...

vue2项目迁移vue3与gogocode的使用

#背景 公司有个项目使用vue2jswebpack框架开发的&#xff0c;由于该项目内部需要安扫&#xff0c;导致很多框架出现了漏洞需要升级&#xff0c;其中主要需要从vue2升vue3,但是重新搭框架推翻重做成本太高&#xff0c;于是找到了gogocode。 #升级步骤踩坑 1. 安装 gogocode插…...

【Python123题库】#数列求和 #百分制成绩转换五分制(循环) #正负交错数列前n项和 #求数列前n项的平方和

禁止转载&#xff0c;原文&#xff1a;https://blog.csdn.net/qq_45801887/article/details/140079866 参考教程&#xff1a;B站视频讲解——https://space.bilibili.com/3546616042621301 有帮助麻烦点个赞 ~ ~ Python123题库 数列求和百分制成绩转换五分制(循环)正负交错数列…...

Edge浏览器选中后,出现AI智能生成 AI专业写作

这个是扩展里边的“ 网页万能复制 & ChatGPT AI写作助手”造成的&#xff0c;这个拓展增加了AI写作功能。关闭这个拓展就解决了。...

c++习题08-计算星期几

目录 一&#xff0c;问题 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;问题 二&#xff0c;思路 首先&#xff0c;需要注意到的是3^2000这个数值很大&#xff0c;已经远远超过了long long 数据类型能够表示的范围&#xff0c;如果想要使用指定的数据类型来保存…...

单目相机减速带检测以及测距

单目相机减速带检测以及测距项目是一个计算机视觉领域的应用&#xff0c;旨在使用一个摄像头&#xff08;单目相机&#xff09;来识别道路上的减速带&#xff0c;并进一步估计车辆与减速带之间的距离。这样的系统对于智能驾驶辅助系统&#xff08;ADAS&#xff09;特别有用&…...

Xilinx FPGA:vivado实现乒乓缓存

一、项目要求 1、用两个伪双端口的RAM实现缓存 2、先写buffer1&#xff0c;再写buffer2 &#xff0c;在读buffer1的同时写buffer2&#xff0c;在读buffer2的同时写buffer1。 3、写端口50M时钟&#xff0c;写入16个8bit 的数据&#xff0c;读出时钟25M&#xff0c;读出8个16…...

解决 VM 虚拟机网络连接异常导致的 Finalshell 无法连接及 ifconfig 中 ens33 丢失问题

在使用 VM 虚拟机的过程中&#xff0c;遇到了一个颇为棘手的网络连接问题。平时虚拟机都能够正常启动并使用&#xff0c;但昨天在启用虚拟机时更换了一下网络节点&#xff0c;结果今天打开虚拟机后。Finalshell 无法连接上虚拟机&#xff0c;并且输入 ifconfig 命令后也没有 en…...

深入Django(三)

Django视图&#xff08;Views&#xff09;详解 引言 在前两天的博客中&#xff0c;我们介绍了Django的基本概念和模型系统。今天&#xff0c;我们将深入探讨Django的视图&#xff08;Views&#xff09;&#xff0c;它们是处理用户请求和返回响应的地方。 什么是Django视图&a…...

观测云赋能「阿里云飞天企业版」,打造全方位监控观测解决方案

近日&#xff0c;观测云成功通过了「阿里云飞天企业版」的生态集成认证测试&#xff0c;并荣获阿里云颁发的产品生态集成认证证书。作为监控观测领域的领军者&#xff0c;观测云一直专注于提供统一的数据视角&#xff0c;助力用户构建起全球范围内的端到端全链路可观测服务。此…...

51单片机第27步_单片机工作在睡眠模式

重点学习51单片机工作在睡眠模式。 1、进入“睡眠模式”的方法 通过将PCON寄存器中的PDWN置1&#xff0c;则CPU会进入“睡眠模式”。在“睡眠模式”中,晶振将停止工作&#xff0c;因此&#xff0c;定时器和串口都将停止工作&#xff0c;只有外部中断继续工作。如果单片机电源…...

互联网应用主流框架整合之SpringCloud微服务治理

微服务架构理念 关于微服务的概念、理念及设计相关内容&#xff0c;并没有特别严格的边界和定义&#xff0c;某种意义上说&#xff0c;适合的就是最好的&#xff0c;在之前的文章中有过详细的阐述&#xff0c;微服务[v1.0.0][Spring生态概述]、微服务[设计与运行]、微服务[v1.…...

超快的 Python 包管理工具「GitHub 热点速览」

天下武功&#xff0c;无坚不破&#xff0c;唯快不破&#xff01; 要想赢得程序员的欢心&#xff0c;工具的速度至关重要。仅需这一优势&#xff0c;即可使其在众多竞争对手中脱颖而出&#xff0c;迅速赢得开发者的偏爱。以这款号称下一代极速 Python 包管理工具——uv 为例&…...

网络基础:OSPF 协议

OSPF&#xff08;Open Shortest Path First&#xff09;是一种广泛使用的链路状态路由协议&#xff0c;用于IP网络中的内部网关协议&#xff08;IGP&#xff09;。OSPF通过在网络中的所有路由器之间交换路由信息&#xff0c;选择从源到目的地的最优路径。OSPF工作在OSI模型的第…...

1456.定长子串中元音的最大数目

思路&#xff1a; 首次是滑动窗口&#xff0c; 然后遍历子字符串&#xff0c;这样复杂度太高&#xff0c;没过测试 改进&#xff0c;滑动窗口先求出第一个窗口中元音数量&#xff0c; 然后利用滑动式&#xff0c;一进一出方式判断首尾是否是原因即可 给你字符串 s 和整数 k 。 …...

基于xilinx FPGA的GTX/GTH/GTY位置信息查看方式(如X0Y0在bank几)

目录 1 概述2 参考文档3 查看方式4查询总结&#xff1a; 1 概述 本文用于介绍如何查看xilinx fpga GTX得位置信息&#xff08;如X0Y0在哪个BANK/Quad&#xff09;。 2 参考文档 《ug476_7Series_Transceivers》 《pg156-ultrascale-pcie-gen3-en-us-4.4》 3 查看方式 通过…...

JAVA小知识30:JAVA多线程篇1,认识多线程与线程安全问题以及解决方案。(万字解析)

来 多线程&#xff0c;一个学起来挺难但是实际应用不难的一个知识点&#xff0c;甚至在很多情况下都不需要考虑&#xff0c;最多就是写测试类的时候模拟一下并发&#xff0c;现在我们就来讲讲基础的多线程知识。 一、线程和进程、并发与并行 1.1、线程和进程 线程&am…...

Python数据分析案例47——笔记本电脑价格影响因素分析

案例背景 博主对电脑的价格和配置一直略有研究&#xff0c;正好最近也有笔记本电脑相关的数据&#xff0c;想着来做点分析吧&#xff0c;写成一个案例。基本上描述性统计&#xff0c;画图&#xff0c;分组聚合&#xff0c;机器学习&#xff0c;交叉验证&#xff0c;搜索超参数…...

【加密与解密】【09】GPG Client签名流程

什么是GPG客户端 GPG客户端是实现PGP加密协议的一套客户端程序&#xff0c;可用于加密或签名 下载GPG客户端 建议安装命令行工具&#xff0c;图形工具一般不具备完整功能 https://gnupg.org/download/index.html生成私钥 此时会要求你输入名称&#xff0c;邮箱&#xff0c…...

“2024软博会” 为软件企业提供集展示、交流、合作一站式平台

随着全球科技浪潮的涌动&#xff0c;软件行业正迎来前所未有的发展机遇&#xff0c;成为了全球新一轮竞争的“制高点”&#xff0c;以及未来经济发展的“增长点”。在当前互联网、大数据、云计算、人工智能、区块链等技术加速创新的背景下&#xff0c;数字经济已经渗透到经济社…...

【Zoom安全解析】深入Zoom的端到端加密机制

标题&#xff1a;【Zoom安全解析】深入Zoom的端到端加密机制 在远程工作和在线会议变得越来越普及的今天&#xff0c;视频会议平台的安全性成为了用户关注的焦点。Zoom作为全球领先的视频会议软件&#xff0c;其端到端加密&#xff08;E2EE&#xff09;功能保证了通话的安全性…...

7 动态规划

下面的例子不错&#xff1a; 对于动态规划&#xff0c;能学到不少东西&#xff1b; 你要清楚每一步都在做什么&#xff0c;划分细致就能够拆解清楚&#xff01; xk​​​​​​​. - 力扣&#xff08;LeetCode&#xff09; labuladong的算法笔记-动态规划-CSDN博客 动态规划是…...

.net 快速开发框架开源

DF.OpenAPI开源系统 前后端分离&#xff0c;开箱即用&#xff0c;java经典功能.net也具备 系统介绍 DF.OpenAPI是基于Admin.NET二开的&#xff0c;是一个开源的多租户后台管理系统。采用前后端分离技术&#xff08;前端使用vue.js&#xff0c;后端使用.net 3~.net6&#xff…...

《昇思25天学习打卡营第06天|网络构建》

网络构建 神经网络模型由神经网络层和Tensor操作构成 #实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2.…...

【链表】- 两两交换链表中的节点

1. 对应力扣题目连接 两两交换链表中的节点 2. 实现案例代码 public class ExchangeLinkedListsPairwise {public static void main(String[] args) {// 示例链表&#xff1a;[1, 2, 3, 4]ListNode head new ListNode(1);head.next new ListNode(2);head.next.next new L…...

java设计模式(四)——抽象工厂模式

一、模式介绍 改善在工厂方法模式中,扩展时新增产品类、工厂类,导致项目中类巨多的场面,减少系统的维护成本,且一个工厂可以生成多种产品,而不是同一种的产品,比如一个工厂既可以生产鞋子又可以衣服,而不是只能生产鞋子。 二、工厂方法模式 1、实现步骤 第一步: 定义…...