学习网络编程No.4【socket编程实战】

引言

北京时间:2023/8/19/23:01,耍了好几天,主要归咎于《我欲封天》这本小说,听了几个晚上之后逐渐入门,在闲暇时间又看了一下,小高潮直接来临,最终在三个昼夜下追完了,哈哈哈!没办法呀,哎!末200章有些些烂尾,结局合乎情理,总的来说优秀,毕竟耳根的名号摆在哪里。过度了两天,辅导员发来了开学通知,时间不允许我们摆烂啦!不然我肯定要把《一念永恒》给追完,哈哈哈!都说《求魔》才是耳根的巅峰,但是我看评论好像《一念永恒》才是经典,具体没看过,有待商榷,不过主要是这种类型的网文有一个缺点,就是容易上头,所以我打算找一个节奏慢的,像《剑来》这种应该就挺适合用听,具体有待尝试。前天晚上睡觉的时候感觉今天的引言有非常多的内容可以写,现在莫名想不起来要说什么了,那就算了,正式进入该篇博客的主题,socket编程实战,使用socket接口简单实现udp客户端/服务器。

在这里插入图片描述

正式学习套接字编程

在上篇博客中,我们重点对有关IP地址和端口号的知识进行了讲解,并且对于数据传输过程以及套接字有了更深的了解,并且对于什么网络字节序和套接字编程相关的接口有了认识,最终因为时间原因只是简单的看了一下对应的socket接口,并没有重点理解这些接口的使用,以及这些接口的功能,所以该篇博客就将重点讲解有关套接字接口的使用以及作用,当然也就是有关socket编程的具体实现,以socket编程实现UDP版本的网通通信为例。

认识sockaddr结构体

在学习socket编程,也就是socket常见的API(接口)之前,我们有必要先进行一个基础概念的梳理,当然此时的这个概念和上篇博客理解IP地址、端口号以及网络字节序不同,此时的这个基础概念是更加宏观的一个概念,本质也可以理解成为什么需要认识sockaddr结构体,sockaddr结构体是什么的问题。

上篇博客中我们反复强调网络通信的本质就是进程间通信的概念,而如果谈到进程间通信,那么我们此时就不得不回忆起进程间通信的两大标准:System V和POSIX,这两大进程间通信标准我们并不陌生,在之前学习多线程之信号量时,重点理解过,并且在上篇博客中,我们讲过socket不仅可以实现本地进程通信(本地套接字),也可以实现网络通信(网络套接字),所以此时两大通信标准的区别就诞生了。什么意思呢?也就是System V进程间通信标准只支持本地进程间通信,不支持网络通信,而因为socket(套接字)中所有的API都是POSIX标准提供和设计的,所以POSIX天然的就是一个既支持本地进程间通信,也支持网络间进程通信的标准,这也就是为什么目前大部分操作系统的内核都是使用POSIX标准的原因。明白了这点之后,此时我可以明白sockaddr本质应该就是POSIX标准下进行的结构体设计,具体用来做什么下述理解,此时我们对socket(套接字)再来一个明确的概念理解,明白socket本质就是一种网络通信技术,它会提供一套API供给我们使用,而使用这套API接口进行编程我们就称为socket网络编程,而常说的socket网络通信本质就是使用socket提供的API进行的进程间通信编码。

明白了上述知识之后,此时对于sockaddr的背景知识我们就了解了,所以此时基于该背景知识,我们就可以很好的进入该话题的理解,也就是因为POSIX标准既支持本地通信,也支持网络通信的特点,所以当时设计POSXI标准的时候,那些顶级的工程师为了实现本地进程通信和网络通信的套接字API(接口)兼容时,他们就提出了sockaddr结构体的方法,因为如果想要实现本地和网络之间的进程通信兼容同一套接口,那么必然就需要通过对接口中参数的改变来实现,所以最后为了实现接口中参数类型不同,而又能传参成功,此时就有了sockaddr_in和sockaddr_un被sockaddr强制类型转换的概念,所以此时我们就明白sockaddr本质是一个共用类型的结构体,而sockaddr_in(网络)和sockaddr_un(本地)才是不同场景下被使用的真正结构体类型,当然具体在POSIX标准下进程通信场景不止这两种,如还有IPV6(sockaddr_in6)等…,如下图所示:

在这里插入图片描述
如上图所示,就是sockaddr、sockaddr_in和sockaddr_un三种不同结构体的地址格式,不同的地址格式也就表示不同结构体对应存储的数据大不相同,从而最终决定什么结构体用于什么场景下的通信,当然这也就是为什么POSIX标准可以实现同一接口在不同场景下使用的重要原因,以sockaddr为公共结构体,然后根据不同场景下的数据去构造不同场景下的不同结构体。并且因为今天我们学习的是网络套接字,所以我们重点学习的就是sockaddr_in结构体,如下图所示,就是sockaddr_in结构体中的变量:

在这里插入图片描述

此时从图中,我们可以非常清晰的看出sockaddr_in结构体中有哪些数据,并且从上篇博客讲的有关IP地址和端口号的知识,此时我们可以很好的理解为什么sockaddr_in表示的是网络套接字通信(IP地址+端口号),但是,此时我们在该结构体中还发现了一个奇怪的数据:__SOCKADDR_COMMON (sin_); 这个玩意是个什么东西呢?从图中我们能看出,它对应的应该是一个16位地址类型AF_INET,那么它们之间存在什么关系呢?具体表示的又是什么意思呢?从上述有关sockaddr_in和sockaddr_un表示两种不同场景下的通信方式,然后在传参的时候需要使用sockaddr类型进行强制类型转换,我们就可以理解:强制类型转换的目的是为了让该目标结构体类型可以被对应的接口识别,那么此时就明白,目标接口本质识别到的一直都是sockaddr类型,那么具体如何去区分传过去的是sockaddr_in,还是sockaddr_un呢?所以为了解决这一问题,此时就设计出了AF_INET和AF_UNIX这两个字段去区分sockaddr_in/sockaddr_un,当然本质就是区分网络通信和本地通信,所以上述所说的__SOCKADDR_COMMON (sin_); 本质就是用来识别对应sockaddr结构体中第一个字段是AF_INET、AF_UNIX还是其它,具体识别方法如下:
在这里插入图片描述
如上图所示,此时我们就发现不同的sockaddr结构体,它们的__SOCKADDR_COMMON 宏定义对应的参数是不一样的,并且此时结合宏定义的具体实现,我们可以发现它使用了##来实现(注:##在C语言中起到一个将两边字符合成一个字符的功能),所以此时对不同结构体宏定义参数的不同以及##的分析,我们就能明白当时在设计sockaddr结构体时,为什么需要这么设计,本质就是为了让不同的结构体类型最终在初始化的时候,有不同的变量可以接收不同的值,也就是最终在sockaddr_in结构体中可以用sin_family变量来接收AF_INET字段,在sockaddr_un结构体中用sun_family变量来接收AF_UNIX字段,在sockaddr_in6中用sin6_family变量接收AF_INET6字段,最终实现使用同一个宏来区分不同的字段,当然本质还是##在起作用,所以此时使用##的好处就在于可以提高代码的复用性、灵活性、可维护性,让我们呢能够根据不同的情况来使用不同的变量,当然这种特性也就是多态的特性,这也就是为什么sockaddr_in、sockaddr_un和sockaddr之间存在多态的根本原因。

把对应结构体中的所有变量搞懂之后,此时我们对sockaddr_in的理解可以说是已臻化境,本质就是在我们初始化sockaddr_in结构体时,需要传入一个标识符来标识该结构体是sockaddr_in,标识我们想要进行的是网络通信,而为了区分各种通信场景,并且实现多态的特性,此时我们就使用了##来区分不同的变量,最后实现不同场景的结构体中标识符变量不同,最终让对应接口在识别是那种结构体,也就是那种标识符时,可以根据不同的变量来识别,如下图代码所示:

在这里插入图片描述
我们以套接字API中最为经典的bind接口为例,先简单来看一看对应接口内部是如何去处理不同场景下的结构体类型,如何识别该结构体内部的第一个字段,具体如上图所示,当然具体bind接口如何使用,下述我们详细介绍。

所以具体有关sockaddr结构体相关的知识我们就讲到这里,下述我们正式进入套接字API的理解,当然先理解sockaddr结构体,再学套接字接口肯定是有原因的,因为套接字接口依赖的就是sockaddr_in结构体,总而言之:在POSIX标准中对sockaddr结构体进行如此设计,此时就可以在不同的协议族(UDP/TCP)、地址类型(系统)和地址长度(IPV4/IPV6)之间进行通信,而不需要改变接口。

学习socket编程有关接口

  • int socket(int domain, int type, int protocol); 功能:创建套接字(本质就是打开一份网络文件),第一个参数domain:表示该套接字是进行网络通信(AF_INET)还是本地通信(AF_UNIX),第二个参数type:表示套接字种类,该套接字是TCP类型还是UDP类型,若传SOCK_STREAM则表示TCP类型(可靠传输、连接、面向字节流),若传SOCK_DGRAM则表示UDP类型(不可靠传输、无连接、面向数据报),第三个参数protocol:默认是0,表示默认让系统根据前两个参数选择使用TCP协议还是UDP协议,返回值int:表示如果创建套接字成功,则返回系统默认为套接字打开文件的文件描述符,失败返回-1,并设置错误码。

  • int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 功能:将sockaddr_in结构体从本地绑定到内核套接字中,第一个参数sockfd:表示创建套接字时返回的文件描述符(存在该参数也就是表示需要将sockaddr_in结构体中的数据写入到该文件描述符对应的文件中),第二个参数addr:是一个sockaddr结构体指针类型,也就是需要把我们初始化完成的sockaddr_in结构体传过去,第三个参数addrlen:本质就是sockaddr_in的长度(大小),返回值int:绑定成功返回0,失败返回-1。

  • ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen); 功能:接收其它主机中套接字发送的数据(网络通信),并记录发送方主机的IP地址和端口号(sockaddr_in) ,第一个参数sockfd:同理表示此时套接字对应返回文件的文件描述符(存在该参数可以明白最后接收的数据肯定就是该文件描述符对应文件中获取的),第二个参数buffer:自己定义的一个存储数据的缓冲区(本质就是用来存储接收到的数据),第三个参数len:定义缓冲区的大小(用来标明你最多可以接收多少数据),第四个参数flags:标示接收数据的方式(阻塞式/非阻塞式),默认设置为0,第五个参数src_addr:同理是一个结构体指针类型,只不过此时的这个指针类型与bind接口中的指针类型不同,它代表的是一个输出型参数,此时传的不再是初始化完成的sockaddr_in结构体,而是一个未初始化的sockaddr_in结构体,本质就是为了作为输出型参数,接收数据发送方的sockaddr_in结构体中的信息(IP地址+端口号),第六个参数addrlen:类型同理是一个指针类型,作为输出型参数,在该接口调用完毕之后,它就会将实际发送方sockaddr_in的大小更新(输出型参数的好处)。返回值ssize_t:最终调用完毕之后,该接口就会返回实际接收数据的字节数。

  • ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); 功能:发送数据到其它主机的套接字中,第一个参数sockfd:同理,套接字对应文件的文件描述符(存在该参数表明最后数据肯定是被发送到了该文件描述符对应的文件中),第二个参数buffer:存储待发送的数据,第三个参数len:待发送数据的大小,第四个参数flags:同理默认为0,第五个参数dest_addr:明白此时发数据一定需要知道目标套接字的sockaddr_in数据,也就是需要知道向谁发数据,所以此时该参数表示的就是目标套接字的sockaddr_in信息(IP地址+端口号),第六个参数addrlen:同理目标套接字sockaddr_in结构体的大小。返回值ssize_t:同理,表示实际发送数据的字节数。

  • uint16_t ntohs(uint16_t netshort); 该接口同理上篇博客所说有关网络字节序相关知识,功能:将数据从网络序列转化为主机序列,一般在从网络中接收数据时使用,参数:16位的网络序列数据,返回值:返回从网络序列转化成主机序列之后的16位主机序列。

  • uint16_t htons(uint16_t hostshort); 同理,功能:将数据从主机序列转化为网络序列,用在需要被网络转述的数据(IP地址和端口号等),参数:16位的主机序列,返回值:返回转化后的16位网络序列。

  • in_addr_t inet_addr(const char *cp); 功能:将IP地址从点分十进制转换为32位无符号整数,并且自带主机序列转网络序列的功能,本质也就是可以把我们日常见到的IP地址转换为允许在网络中传输的数据,参数:需要被转换的字符串类型IP地址,返回值:成功返回转换之后的32位无符号整形,失败则返回INADDR_NONE。

  • char *inet_ntoa(struct in_addr in); 功能:同理,将IP地址从32位无符号整数转化为点分十进制的形式,并自带将网络序列转化为主机序列,参数:一个32位无符号整形的IP地址,返回值:转换之后的点分十进制形式的IP地址。

正式开始UDP客户端/服务器代码编写

搞定了上述常见套接字接口之后,此时实现一份网络通信形式的代码对于我们来说可以说是不费吹灰之力,本质和我们之前学习进程间通信,使用管道或者共享内存实现一份本地进程间通信的代码一样,只需要把步骤和需要初始化的数据搞定,最后直接使用socket为我们提供的数据发送和数据接收接口,很轻松就能将整份代码搞定。所以下面我们就分为三个场景来实现我们的服务端和客户端,由浅入深将我们的客户端和服务端一步一步完善。

首先是客户端的代码实现

此时因为我们想要实现的是三种不同场景下的服务端代码,而服务端代码的改变并不改变客户端,所以此时明白服务端代码有三份,而客户端的代码大致都是相似的,主要起的功能就是向服务端发送数据,接收服务端传回来的数据,所以如下图所示,就是使用socket编程实现的UDP客户端:

在这里插入图片描述
明白,此时对于客户端而言,还有一个问题需要我们解决,本质也就是理解为什么服务端关心的是自己的IP地址和端口号,而客户端关心的也是服务器的IP地址和端口号, 对比服务端和客户端的代码我们发现,在进行sockaddr_in初始化时初始化的都是服务器的IP地址和端口号,那么第一个问题就来了,为什么客户端不需要设置自己的IP地址和端口号呢?原因是因为:在我们的电脑主机上存在非常多的客户端,如果让客户端像服务端一样自己设置端口号,那么就有可能会导致两个客户端设置的端口号相同,那么此时就会导致客户端启动冲突,因为socket网络通信的本质就是 [client_ip、client_port和server_ip、server_port] 两个进程之间的通信,所以对于客户端而言,它的端口号和IP地址都是操作系统统一分配的,在发送数据时操作系统同理会将对应的端口号和IP地址绑定到该主机的套接字,然后发送给服务端套接字,从而让服务端最终也能通过recvfrom接口顺利拿到客户端的sockaddr_in数据,这也就是为什么无论是服务端还是客户端它们关心的都是服务端的IP地址和端口号了,换一个角度来看,本质也就是取决于服务端是先收后发,而客户端是先发后收的原理,再本质一点来看也就是套接字的使用规则和网络通信的基本原理决定的。

其次是服务端代码的编写

搞定了有关客户端的知识,此时我们正式进入三个不同场景服务端代码的编写,本就就是一个逐渐深入,代码逐渐丰富,逐渐变化的一个过程,如下场景一、场景二、场景三所示。

场景一:客户端发消息给服务端,服务端将消息进行回显

此时该场景是三种场景下最简单的一种,也是socket编程最为简单的一种运用,总体socket的使用规则已包含在其中,当然对于现在的我们(搞懂sockaddr_in和API),这种场景还是非常基础和实用的,下述两种场景本质万变不离其宗,更多的是对代码能力和C++语法的熟练使用而已,现在就让我们一起来看看如何实现socket最基础的使用吧!如下代码所示:

在这里插入图片描述

场景二:客户端发消息给服务端,服务端对消息进行处理,返回处理后的数据

该场景相比于场景一,有关使用套接字实现网络通信以及数据接收和转发本质都没有任何区别,因为这一套就是套接字编程的使用规则,最大的区别就是我们在服务器中增加了一个实现数据处理的函数指针,然后我们对其进行了数据处理函数的初始化,让其具有了处理数据的功能,并且此时我们使用到了一个popen接口,所以此时我们的服务器就具备了处理指令的能力,具体如图示,下面就是代码实现:

在这里插入图片描述


处理指令之后的结果,如图所示:
在这里插入图片描述

所以如上图所示,此时我们就可以实现将本地客户端中输入相关的指令,然后通过网络的形式传到某个专门处理或者说可以处理该指令的服务端上,然后该服务端处理该指令,最后将指令处理完成之后的数据返回给我们,所以根据这一原理,这不就是我们使用云服务器构建xshell机器的过程吗?让xshell将我们本地输入的指令发送到远端服务器上,然后通过服务器发送到xshell的服务端上,然后xshell根据我们在云服务器上的数据和输入的指令,进行处理,最后返回处理结果,这样我们就获取到了对应指令产生的功能,这不就是最经典的网络通信过程吗?哈哈哈,具体有待深入学习,这里先简单理解一下就行。

场景三:客户端发消息给服务端,服务端将收到的消息全部返回给客户端

这个功能不能说是上述场景二的进阶,只能说是一个相辅相成的存在,因为一个服务端的代码设计和逻辑肯定是非常复杂的,需要实现的功能和完成的效果非常多,但是因为该代码设计多线程相关知识,所以我们将其称为场景三,本质就是实现一个群聊效果,让服务端中一个线程负责接收数据,一个线程负责发送数据,然后每次都会将所有数据发送给所有在线用户,所以因为该部分代码改动较大,客户端也需要通过多线程来控制,所以客户端代码也会展示,如下代码所示:

首先是服务端代码实现

在这里插入图片描述


其次是客户端代码实现

在这里插入图片描述
上述就是有关实现网络群聊效果的UDP服务器和客户端,当然代码只是基础实现,但是麻雀虽小五脏俱全,我们想要实现的预期效果是有的,本质逻辑就是让服务器保存所有发送数据主机的IP地址和端口号,然后将服务器接收到的任意消息广播给所有在线用户,以这一逻辑实现方法有很多,上述只是其中一种,所有有关UDP实现网络通信服务器和客户端的知识我们就理解到这里。

总结:有关使用socket编程实现UDP版本的网络通信知识我们就了解到这,下篇博客我们再来看看如何使用socket编程实现TCP版本的网络通信吧!See you!

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

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

相关文章

在 Pytorch 中使用 TensorBoard

机器学习的训练过程中会产生各类数据,包括 “标量scalar”、“图像image”、“统计图diagram”、“视频video”、“音频audio”、“文本text”、“嵌入Embedding” 等等。为了更好地追踪和分析这些数据,许多可视化工具应运而生,比如之前介绍的…

使用 ChatGPT 创建 PowerPoint 演示文稿

让 ChatGPT 成为您的助手来帮助您编写电子邮件很简单,因为众所周知,它非常能够生成文本。很明显,ChatGPT 无法帮助您做饭。但您可能想知道它是否可以生成文本以外的其他内容。在上一篇文章中,您了解到 ChatGPT 只能通过中间语言为您生成图形。在这篇文章中,您将了解使用中…

Ubuntu 配置国内源

配置国内源 因为众所周知的原因,国外的很多网站在国内是访问不了或者访问极慢的,这其中就包括了Ubuntu的官方源。 所以,想要流畅的使用apt安装应用,就需要配置国内源的镜像。 市面上Ubuntu的国内镜像源非常多,比较有…

PyTorch训练简单的生成对抗网络GAN

文章目录 原理代码结果参考 原理 同时训练两个网络:辨别器Discriminator 和 生成器Generator Generator是 造假者,用来生成假数据。 Discriminator 是警察,尽可能的分辨出来哪些是造假的,哪些是真实的数据。 目的:使…

小区新冠疫情管理系统的设计与实现/基于springboot的小区疫情管理系统

摘要 采用更加便于维护和使用的Java语言,其可拓展性高且更富于表现力,基于mysql数据库、Springboot框架开发的小区新冠疫情管理系统,方便用户查看物资信息、疫苗信息。通过Eclipse来进行网页编程,其方便易用、移植适用性广、更加安…

日志搞不定?手把手教你如何使用Log4j2

系列文章目录 从零开始,手把手教你搭建Spring Boot后台工程并说明 Spring框架与SpringBoot的关联与区别 SpringBean生成流程详解 —— 由浅入深(附超精细流程图) Spring监听器用法与原理详解 Spring事务畅谈 —— 由浅入深彻底弄懂 Transactional注解 面试热点详解…

装备制造企业如何执行精益管理?

导 读 ( 文/ 2358 ) 精益管理是一种以提高效率、降低成本和优化流程为目标的管理方法。装备制造行业具备人工参与度高,产成品价值高,质量要求高的特点。 在装备制造企业中实施精益管理可以帮助企业提高竞争力、提升生产效率并提供高质量的产品。本文将…

边缘计算节点BEC典型实践:如何快速上手PC-Farm服务器?

百度智能云边缘计算节点BEC(Baidu Edge Computing)基于运营商边缘节点和网络构建,一站式提供靠近终端用户的弹性计算资源。边缘计算节点在海外覆盖五大洲,在国内覆盖全国七大区、三大运营商。BEC通过就近计算和处理,大…

【算法日志】贪心算法刷题:单调递增数列,贪心算法总结(day32)

代码随想录刷题60Day 目录 前言 单调递增数列 贪心算法总结 前言 今天是贪心算法刷题的最后一天,今天本来是打算刷两道题,其中的一道hard题做了好久都没有做出来(主要思路错了)。然后再总结一下。 单调递增数列 int monotoneIncreasingDigits(int n…

Wlan——STA上线流程与802.11MAC帧讲解以及报文转发路径

目录 802.11MAC帧基本概念 802.11帧结构 802.11MAC帧的分类 管理帧 控制帧 数据帧 STA接入无线网络流程 信号扫描—管理帧 链路认证—管理帧 用户关联—管理帧 用户上线 不同802.11帧的转发路径 802.11MAC帧基本概念 802.11协议在802家族中的角色位置 其中802.3标…

Linux内核学习(八)—— 内存管理(基于Linux 2.6内核)

目录 一、页(page) 二、区(zone) 三、页操作 四、kmalloc() 五、vmalloc() 六、slab 分配器 七、在栈上的静态分配 一、页(page) 内核把物理页作为内存管理的基本单位。尽管处理器的最小可寻 …

网工内推 | 锐捷招云工程师,HCIE、CCIE、RHCE优先,25k*13薪

01 锐捷网络 招聘岗位:云方案工程师 职责描述: 1、负责云数据中心方案项目方案设计撰写、项目实施交付、故障处理、业务割接、客户培训、现场保障、网络优化、网络巡检等技术相关业务 2、负责云数据中心方案新技术文档沉淀、体系建设、工具开发等标准化…

使用element-plus组件,默认显示英文 转换为中文

最近在边写项目边学习vue3 所以这几天没有更新 找机会把vue3的知识也统计一下吧 先说今天遇到的问题 最近做项目的时候使用element-plus分页组件时发现&#xff0c;显示的不是中文的了&#xff0c;是英文的 解决方法 在app.vue里面配置 <template><el-config-provi…

Pyqt5打开电脑摄像头进行拍照

目录 1、设计UI界面 2、设计逻辑代码&#xff0c;建立连接显示窗口 3、结果 1、设计UI界面 将ui界面转为py文件后获得的逻辑代码为&#xff1a;&#xff08;文件名为 Camera.py&#xff09; # -*- coding: utf-8 -*-# Form implementation generated from reading ui file …

【算法专题突破】双指针 - 移动零(1)

目录 写在前面 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 写在前面 在进行了剑指Offer和LeetCode hot100的毒打之后&#xff0c; 我决心系统地学习一些经典算法&#xff0c;增强我的综合算法能力。 1. 题目解析 题目链接&#xff1a;283. 移动零 - 力…

centos7.9和redhat6.9 离线升级OpenSSH和openssl (2023年的版本)

升级注意事项&#xff01; 1、多开几个连接窗口&#xff08;xshell&#xff09;&#xff0c;避免升级openssh失败无法再次连接终端&#xff0c;否则要跑机房了。 2、可开启telnet服务、vnc服务、打快照。多几个“保命”的路数。一、centos7.9的信息 [rootnode2 ~]# openssl v…

学会Mybatis框架:一文掌握MyBatis与GitHub插件分页的完美结合【三.分页】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Mybatis的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Mybatis分页 1. Mybatis自带分页 2…

AIGC如何借AI Agent落地?TARS-RPA-Agent破解RPA与LLM融合难题

文/王吉伟 大语言模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;的持续爆发&#xff0c;让AIGC一直处于这股AI风暴最中央&#xff0c;不停席卷各个领域。 在国内&#xff0c;仍在雨后春笋般上新的大语言模型&#xff0c;在持续累加“千模大战”大模型数量的…

Linux之基础IO文件系统讲解

基础IO文件系统讲解 回顾C语言读写文件读文件操作写文件操作输出信息到显示器的方法stdin & stdout & stderr总结 系统文件IOIO接口介绍文件描述符fd文件描述符的分配规则C标准库文件操作函数简易模拟实现重定向dup2 系统调用在minishell中添加重定向功能 FILE文件系统…

什么是Pytorch?

当谈及深度学习框架时&#xff0c;PyTorch 是当今备受欢迎的选择之一。作为一个开源的机器学习库&#xff0c;PyTorch 为研究人员和开发者们提供了一个强大的工具来构建、训练以及部署各种深度学习模型。你可能会问&#xff0c;PyTorch 是什么&#xff0c;它有什么特点&#xf…