linux网络版计算机

news2024/12/28 11:20:16

文章目录

  • 前言
  • 一、网络版计算机
    • 1.序列化与反序列化
    • 2.网络版计算机实现
    • 3.守护进程
    • 4.json格式


前言


一、网络版计算机

1.序列化与反序列化

协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢?
例如, 我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 最后再把结果返回给客户端。

约定方案一:
客户端发送一个形如"1+1"的字符串;
这个字符串中有两个操作数, 都是整形;
两个数字之间会有一个字符是运算符, 运算符只能是 + ;
数字和运算符之间没有空格;

约定方案二:
定义结构体来表示我们需要交互的信息;
发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体;
这个过程叫做 “序列化” 和 “反序列化”

2.网络版计算机实现

下面我们就采用约定方案二来指定一个网络版计算机传输数据的协议。
我们先来实现一个Sock套接字类,该类封装了创建套接字,绑定套接字等一些接口,以方便构建服务器使用。
在这里插入图片描述
然后我们使用刚刚封装的Sock接口来创建一个TcpServer。在TcpServer中每当有一个连接时,我们就创建一个线程来处理这个连接请求。我们应该在线程回调函数ThreadRoutine中调用用户向该服务器传入的需要执行的函数func_。但是因为ThreadRoutine函数为静态成员函数,不能访问非静态成员变量,所以我们无法在ThreadRoutine函数中调用func_。
在这里插入图片描述
我们可以采用下面的解决办法,我们在要传递给线程回调函数的参数类型ThreadData中封装一个TcpServer * 类型的指针,然后当ThreadRoutine函数收到参数后,根据传进来的TcpServer * 类型的指针来调用TcpServer对象的成员函数就可以了。这样我们就解决了静态成员函数ThreadRoutine调用TcpServer对象的非静态成员函数的问题。可以看到,我们在Excute函数中调用了TcpServer对象的func_函数,这样在ThreadRoutine函数中,每个线程就可以通过TcpServer * 指针来调用Excute函数来执行func_函数了。
在这里插入图片描述
如果我们向让TcpServer做一系列操作的话,那么我们可以创建一个vector容器,然后将函数都添加到vector容器中,然后可以调用TcpServer对象的BindHandler函数来添加一个函数,也可以调用TcpServer对象的Excute函数来执行vector容器中的所有函数。我们还可以将每个操作都进行命名,那么我们就需要使用map容器来存储操作名和对应的操作函数了,在调用TcpServer对象的BindHandler函数添加函数时需要为这个操作传入一个名称。
在这里插入图片描述
然后我们基于TcpServer再来搭建计算器服务器。我们先在TcpServer服务器中添加一个debug函数来测试服务器是否可以成功执行添加的debug函数。
在这里插入图片描述
然后我们编写makefile文件后开始进行测试。
在这里插入图片描述
我们看到CalServer服务器收到了客户端发来的消息,即TcpServer服务器执行了CalServer中的debug函数,因为debug函数只是打印一个字符串,所以当这个debug执行完后就关闭了这次连接。
在这里插入图片描述
下面我们将calculator函数添加到TcpServer函数中,calculator函数以后就用来处理客户端发送过来的计算请求。
在这里插入图片描述
下面我们再来手动进行协议定制,我们在Protocol中进行协议的定制,我们规定客户端的计算请求由一个Request类对象来描述,该对象的x_ 和 y_成员变量表示计算的两个操作数,op_成员变量表示计算的操作符。服务器返回一个Response类对象来表示计算结果,该对象的result_成员变量就是计算结果,code_成员变量标识这次计算是否出现了错误。
在这里插入图片描述
通过上面的描述我们知道了客户端发送的请求为一个Request类类型对象,二服务器返回的结果是一个Response类类型的对象。我们在前面只学习了通过套接字传递字符串,所以我们可以先在客户端将Request类类型对象转换为字符串,然后再通过套接字传递给服务器这个字符串。将Request类类型对象转换为字符串的过程就可以称为序列化。服务器收到客户端发送的字符串后,再通过某种规则将这个字符串解析还原为Request对象,即将字符串转换为Request对象,这个过程就是反序列化。服务器拿到Request对象后进行计算,然后将计算结果封装到一个Response对象中,当服务器将Response对象传递给客户端时,也需要先将Response对象转换为字符串然后放到套接字中进行传递,即先将Response对象进行序列化。然后客户端从套接字中收到服务器返回的字符串后,需要先根据定制好的规则将这个字符串解析为Response对象,然后拿到该对象中保存的运算结果和运算结果状态码,这个过程就是反序列化。
在这里插入图片描述
下面我们先实现Request类的序列化函数Serialize函数。下面的实现使用条件编译的原因是因为我们先实现自己定制的序列化和反序列化函数,但是后面我们还会使用其它已经写好的序列化和反序列化函数,条件编译方便了以后序列化使用自己写的函数还是使用其它已经写好的函数。我们自己定义的序列化函数是将操作数x_与操作符中间添加一个空格,然后将操作符与操作数y_之间添加一个空格,然后将这个string对象返回即可。需要注意的是因为op_已经为一个字符了,所以我们不需要使用to_string来将这个字符转换为字符串,因为to_string会将字符op_的ASCII码转换为字符串。例如字符op_如果为+号,+号的ASCII码为43,那么to_string(op_)就会将43转换为字符串。
在这里插入图片描述
下面我们再来实现Request类的反序列化函数Deserialized函数,我们以空格为分隔符,将字符串中包含的x_、y_、op_都解析出来。
在这里插入图片描述
然后我们再来使用Response类的序列化和反序列化函数。
在这里插入图片描述
然后我们再实现Recv函数和Send函数,Recv函数会从套接字文件中读取数据并返回。Send函数会将数据写到套接字文件中。
在这里插入图片描述
然后我们再来实现CalServer服务器中的处理计算的函数calculator。在calculator函数中通过calculatorHelper函数来进行计算。
在这里插入图片描述
下面我们来实现calculatorHelper函数。
在这里插入图片描述
这样我们就简单的实现了CalServer,下面我们来实现CalClient客户端程序。
客户端不需要bind绑定,但是需要连接到服务器,所以我们还需要在Sock类中添加一个Connect连接服务器的接口。
在这里插入图片描述
然后我们来实现客户端,我们让客户端每1秒将一个计算式发过去,然后打印出来服务器发送回来的计算结果。
在这里插入图片描述
我们看到测试的结果和我们预期的一样。
在这里插入图片描述
下面我们将客户端改为用户输入,然后让服务器计算用户输入的算式,将答案返回给用户。
在这里插入图片描述
在这里插入图片描述
但是我们的服务器还存在bug,当我们将客户端退出后,服务器也出错并且退出了,这是肯定不行的。这是因为当我们将客户端退出后,此时客户端就断开连接并且不会向sock套接字中写入数据了,并且也不会读取数据了,而在CalServer服务器中还会调用Recv函数从套接字文件中读取数据,因为此时套接字文件的写端客户端已经关闭了,所以Recv会读到空字符串并且返回给服务器,然后服务器将空字符串解析出来计算结果,此时虽然没有解析出来Request对象,但是Request对象的x_和y_都为随机值,所以也会计算出来一个结果,然后将这个结果写入到套接字中,但是这一步就会出错,因为此时套接字文件的读端客户端已经关闭了,而服务器还向这个套接字文件中写入数据就会产生SIGPIPE信号了,即操作系统不允许这样的情况出现,所以服务器就出错了。
在这里插入图片描述
下面我们来解决这个问题,我们先在服务器中判断从Recv函数中是否读取到了数据,如果读取到了数据就向下执行计算的操作,如果没有读取到数据就不再进行数据读取。因为此时客户端已经退出了,所以将服务器的处理请求的线程也退出。然后我们看到此时服务器就不会出现错误了。
在这里插入图片描述
在这里插入图片描述
但是我们上述还没有彻底解决问题,因为以后可能会出现这样的情况,当服务器想要给客户端send返回数据时,而此时客户端退出了,那么服务器就会产生非法写入的问题,即文件的读端已经关闭,写端还要写入数据那么就会发生非法写入的问题。所以我们一般都要让服务器忽略SIGPIPE信号,这样当产生上面的情况时,服务器并不会崩溃。这样的情况是我们在写服务器时经常遇到的情况,所以需要特别注意。
在这里插入图片描述
我们的程序还会存在一个问题,即我们不能保证Recv函数每次读取的就是一条完整的计算式字符串。因为TCP通信是面向字节流的,即什么样的字符串组合都有可能被读取到。例如读取到" 1234 + 5678 / 334 * "这样的字符串,这样的字符串在进行反序列化时就会出现错误。所以我们的Recv函数中并不能保证每次读取的都是一个完整完善的请求。
下面是面向字节流通信,send等系统调用接口其实就是将buffer里面的数据拷贝到客户端的发送缓存区中,然后由发送缓冲区来将数据发送到网络中。在服务器中有一个接收缓冲区,该缓冲区中存放的是服务器从网络中读取的数据,recv等系统调用接口其实就是将接收缓冲区里面的数据拷贝到服务器的buffer中。发送缓冲区和接收缓冲区是面向字节流通信的,即通信的数据并不是每次都是一个请求,有可能客户端发送了很多个请求,然后发送缓冲区等满了之后才发送,读取缓冲区也并不是每次读取一个请求,而是读取一大串字节流数据。所以我们就不能保证读取时每次都读取到一个完善完整的请求。所以我们需要对协议进行进一步的定制。
在这里插入图片描述
我们首先需要在客户端发送的序列化好的数据中做改动,即不能让客户端只发送计算式组成的字符串,应该在这个字符串的前面和后面加一些分隔符来区分这个计算式字符串,然后在前面加上计算式字符串的长度,这样来表示一次请求,这样进行封装的话可以更好的区分客户端发来的一个请求。
在这里插入图片描述
然后我们改变Recv函数,判断Recv函数调用recv系统调用的执行结果,如果读取到了数据就返回true表示这次读取到了数据,如果没有读取到数据或者写端已经关闭就返回false,表示这次没有读取到数据。如果读取到了数据就会追加到输出型参数out中。即Recv函数就用来处理读取数据和对写端进行判断,如果文件中还有数据并且写端没有关闭,那么就读取数据并且将数据追加到out中然后返回true,如果写端关闭或者读取失败就返回false。
在这里插入图片描述
然后我们在CalServer服务器的处理请求的calculator函数中先调用Recv函数进行读取数据,如果从套接字文件中读取数据都失败了,那么说明客户端已经关闭了,所以服务器就可以直接退出这一次处理函数了。如果Recv函数读取到了数据,那么就调用Decode函数来从inbuffer读取的数据中解析一个完整完善的请求报文,如果没有解析出来就说明inbuffer中没有包含完整完善请求报文的数据,那么可以继续从套接字文件中进行数据读取。如果Decode函数返回的package不为空,那么就说明package中此时已经有且仅有一个完整完善的请求报文,然后下面就可以对这个请求报文进行处理了。
在这里插入图片描述
然后我们来实现Decode函数,我们控制Decode函数只有分析到一个完整完善的请求报文时才进行数据返回,如果没有分享到完整完善的报文,那么就返回空字符串。
在这里插入图片描述
在这里插入图片描述
这样我们就保证了服务器获取请求报文并进行计算时不会出现问题,但是当服务器返回处理好的结果时,我们也需要将这个结果进行序列化,然后将序列化好的字符串调用Encode函数进行封装,Encode会返回一个完整的返回报文。然后再调用Send函数将这个完整完善的返回报文写到套接字文件中。
在这里插入图片描述
下面我们来实现Encode函数,Encode函数就是将有效字符串的前面加上长度信息,然后通过SEP分隔符来将有效字符串分割开。需要注意的是请求报文和返回报文都可以使用Decode函数来进行解析有效字符串,都可以使用Encode函数来进行封装有效字符串。
在这里插入图片描述
下面我们再来将客户端发送请求报文和接收返回报文的处理也进行修改。其中quit变量用来控制客户端是否关闭,当服务器关闭时,客户端读取返回数据就会失败,然后改变quit为true,那么就不会进入下一次循环来让用户输入计算式了,即客户端就关闭了。
在这里插入图片描述
经过测试我们看到客户端和服务器可以正常运行并且进行通信。
在这里插入图片描述
下面我们在服务器中打印出来封装前和封装后,解析前和解析后的数据来进行观察。
在这里插入图片描述
然后我们在客户端中将用户输入的格式改变,然后再判断服务器返回的结果中的code_错误码来打印出对应的错误信息,如果没有错误就打印出计算的结果。
在这里插入图片描述
通过测试我们就可以看到客户端和服务器更加完善了。
在这里插入图片描述
下面我们再来将服务器输出到显示器中的信息改为输出到日志文件中。我们看到服务器的一些输出信息都在日志文件中了。
在这里插入图片描述
在这里插入图片描述

3.守护进程

现在我们的服务器进程为一个前台进程,即该进程和终端关联,当运行这个进程时,在命令行输入其它命令时是无效的。但是这样的前台进程当我们退出这一次登录时,这个进程也会关闭,那么我们的服务器进程运行时也会被退出,这肯定是不行的,因为服务器进程只要运行了就不能再退出的。所以此时我们就需要将服务器进程变为一个守护进程。

1.前台进程:和终端进程关联的进程。
2. 任何xshell登录,只允许一个前台进程和多个后台进程。
3. 进程除了有自己的pid,ppid,还有一个组ID。
4. 在命令行中,同时用管道启动多个进程,这多个进程是兄弟关系,父进程都是bash->可以用匿名管道来进行通信。
5. 而同时被创建的多个进程可以成为一个进程组的概念,这个进程组的组长一般是第一个进程。
6. 任何一次登录的用户,需要有多个进程组来给这个用户提供服务的(bash),用户自己也可以启动很多进程或者进程组,我们把给用户提供服务的进程或者用户自己启动的所有的进程或者进程组整体属于一个叫做会话的机制中。
7. 那么我们在bash命令行中启动的服务器进程也属于这个会话,如果我们将这次登录退出,那么这个会话中的所有进程都会被退出,即服务器进程也会被退出。所以我们需要将服务器进程自成一个会话,变为守护进程,那么当我们退出这一次登录时,自成一个会话的服务器进程就不会退出了,这就是守护进程。

在这里插入图片描述
在这里插入图片描述
但是setsid要成功被调用,必须保证当前进程不是进程组的组织,所以我们就需要先使用fork让服务器进程不为第一个进程。下面我们来使用代码实现将服务器进程变为守护进程。
在这里插入图片描述
然后我们在启动CalServer服务器时先将这个进程变为守护者进程。
在这里插入图片描述
我们看到此时服务器进程server的父进程的pid为1,此时server进程已经自成一个会话了,我们退出xshell这次登录然后再次登录时,这个server进程还在运行,因为我们没有关闭server进程的会话,所以server进程就可以一直运行了。此时我们想要关闭server进程就只能通过kill命令和pid来将server进程关闭了。守护进程本质是孤儿进程的一种,它与孤儿进程不同的就是守护进程自成一个会话。
在这里插入图片描述
在这里插入图片描述

4.json格式

上面我们用自己实现的协议进行了序列化和反序列化,但是我们自己实现的序列化和反序列化肯定是不完善的,所以我们下面来使用JSON格式。
因为json不是c++自带的类型,所以如果我们想要使用json类型,就需要先下载json库。下面我们来安装jsoncpp库。

sudo yum install jsoncpp-devel

在这里插入图片描述

JSON(JavaScript ObjectNotation)是一种轻量级的数据交换格式,常用于在不同系统之间传输和存储数据。它具有以下特点:

  1. 可读性:JSON使用文本格式表示数据,易于阅读和理解。它采用了类似于JavaScript对象的键值对的形式来组织数据。
  2. 简洁性:JSON的语法非常简洁,相比于其他数据格式(如XML),它的数据表示更为紧凑,节省了传输和存储空间。
  3. 支持多种数据类型:JSON支持多种基本数据类型,包括字符串、数字、布尔值、数组、对象和null。这使得JSON非常灵活,可以表示各种类型的数据结构。
  4. 易于解析和生成:JSON数据可以轻松地由各种编程语言解析和生成。许多编程语言都提供了内置的JSON解析器和生成器,使得处理JSON数据变得简单和方便。
  5. 跨平台和语言无关:由于JSON是一种通用的数据格式,它不依赖于任何特定的平台或编程语言。这意味着JSON可以在不同的系统和不同的编程语言之间进行数据交换和共享。
  6. 可扩展性:JSON支持嵌套结构,允许在对象中嵌套其他对象或数组,从而实现复杂的数据结构。这种嵌套结构可以实现数据的层级关系和组织。
  7. 平台无关的数据交换格式:由于JSON的广泛支持和普及性,它已成为一种通用的数据交换格式。许多Web服务和API都使用JSON作为数据交换的标准格式。

例如下面表示一个包含个人信息的JSON对象。它包括名称、年龄、是否是学生、兴趣爱好和地址等属性。注意JSON中使用双引号表示键和字符串值,使用逗号分隔不同的键值对,使用方括号表示数组,使用花括号表示对象。

{
  "name": "John",
  "age": 18,
  "isStudent": true,
  "hobbies": ["runing", "traveling"],
  "address": {
    "street": "999 Main St",
    "city": "hangzhou"
  }
}

基本语法:

①.Json 键值对:键值对是 Json 的基本构成。其中,名称即对象的属性名称,必须包含在双引号( " " )中;值即对象对应的属性值;名称和值之间用冒号( : )隔开。
②.Json 值:Json 的值可以是以下几种:字符串、数字( 整型、浮点型 )、布尔值( ture、false )、空值( null )、数组、对象。
③.Json 对象:Json 对象是用大括号( {、} )括起来的一系列 Json 键值对的集合,键值对之间用逗号( , )隔开。
④.Json 数组:Json 数组是用中括号( [、] )括起来的一系列 Json 值的集合,值之间用逗号( , )隔开。

下面我们来使用json数据格式写一个测试程序。
下面为使用json来将数据进行序列化,我们使用了StyleWriter对象的write来将json对象转为字符串,可以看到下面的结果就是序列化之后的json对象。并且我们需要注意,因为我们使用了json库中的方法和变量等,所以我们在编译时需要加上jsoncpp库。
在这里插入图片描述
在这里插入图片描述
下面我们再使用FastWriter对象的write方法将json对象序列化为字符串,我们看到此时序列化之后的字符串没有了多余的空格和换行,变得更精简了。
在这里插入图片描述
我们还可以把一个json对象放到另一个json对象中。
在这里插入图片描述
在这里插入图片描述
下面我们就将网络版计算机中的序列化和反序列化的过程使用json库提供的序列化和反序列化方法实现。
json库的头文件在jsoncpp/json文件夹下,所以我们需要将路径都包含清楚。
在这里插入图片描述
下面我们将Request类的序列化和反序列化函数中使用了json库提供的序列化和反序列化方案,我们看到使用json库提供的方法更简便了。
在这里插入图片描述
然后我们也将Response类中的序列化和反序列化操作使用json库提供的方法。
在这里插入图片描述
我们看到使用json库题库的序列化和反序列化方案的话,那么在客户端中我们就没有打印出用户输入的计算式。
在这里插入图片描述
我们此时可以在协议中做扩展,在Response类中也将计算式的内容存储。那么我们在访问Response类对象时也可以访问到用户输入的计算式了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后我们进行测试就可以看到,用户输入的计算式也被打印出来了。到此我们就简单实现了一个网络版计算器。
在这里插入图片描述

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

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

相关文章

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界 写在最前面观后感其他有趣的专题课程 写在最前面 嘿,你是不是对科技和创新充满好奇?2023 英特尔 On 技术创新大会线上活动邀请你一起探索最前沿的科技世界! 这不仅是一场普通的聚会&…

关于“Python”的核心知识点整理大全31

目录 12.4.2 在屏幕上绘制飞船 alien_invasion.py ​编辑12.5 重构:模块 game_functions 12.5.1 函数 check_events() game_functions.py alien_invasion.py 12.5.2 函数 update_screen() game_functions.py alien_invasion.py 12.6 驾驶飞船 12.6.1 响应…

uniapp websocket的使用和封装

在uniapp中socket分为两种形式,第一种适用于只有一个socket链接,第二种适用于多个socket链接。传送门 这里以socketTask为列子封装 在utils新建一个文件 在你要使用的页面引入,我这是聊天那种,所以我在拿到用户信息之后连接sock…

某电子文档安全管理系统 SQL注入漏洞复现

漏洞介绍 亿赛通电子文档安全管理系统 (简称: CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护…

【小沐学Unity3d】3ds Max 减面工具汇总

文章目录 1、简介2、“优化”修改器3、“专业优化”修改器4、“多分辨率”修改器5、Polygon Cruncher5.1 工具简介5.2 下载安装5.3 使用测试 6、Simplyon6.1 工具简介6.2 下载安装6.3 使用测试 7、FAQ7.1 在3dmax里面显示点数和面数 结语 1、简介 有几个 3ds Max 修改器可帮助您…

在线更换Proxmox VE超融合集群Ceph OSD磁盘

因为资源紧张的原因,担心一旦关机,虚拟机因为没有空闲的资源而被冻结,以致于不能漂移,导致部分服务停止,只好让机房帮忙热插拔。 幸运的是,插上去能够被系统所识别(/dev/sdf就是新插入的硬盘&am…

深入理解 Spring Boot:核心知识与约定大于配置原则

深入理解 Spring Boot:核心知识与约定大于配置原则 简单说一下为什么要有 Spring Boot? 因为 Spring 的缺点。 虽然 Spring 的组件代码是轻量级的,但它的配置却是重量级的(需要大量 XML 配置) 为了减少配置文件,简化开发 Spri…

MaBatis使用`ResultMap`标签手动映射详解使用

文章目录 MaBatis使用ResultMap标签手动映射详解使用1、MyBatis只能自动维护库表”列名“与”属性名“相同时的对应关系,二者不同时无法自动ORM,如下:2、在SQL中使用 as 为查询字段添加列别名,以匹配属性名:但是如果我…

JDBC的使用

目录 JDBC简介 JDBC的使用 JDBC简介 JDBC(Java DataBase Connectivity)是用Java操作数据库的一套API。 sun公司官方定义的一套操作所有关系型数据库的规范,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)来编…

神经网络:优化器和全连接层

SGD(随机梯度下降) 随机梯度下降的优化算法在科研和工业界是很常用的。 很多理论和工程问题都能转化成对目标函数进行最小化的数学问题。 举个例子:梯度下降(Gradient Descent)就好比一个人想从高山上奔跑到山谷最低…

提升数据处理技巧:Python正则表达式的高级应用

提升数据处理技巧:Python正则表达式的高级应用 引言:探索正则表达式的高级应用高级匹配技巧使用正则表达式处理复杂数据正则表达式的性能优化正则表达式的局限和替代方案 引言:探索正则表达式的高级应用 在数据驱动的世界里,有效…

机器学习笔记:支持向量机回归SVR

1 主要思想 主要思路类似于机器学习笔记:支持向量机SVM_支撑向量学习-CSDN博客 和SVM的区别主要有 解法和SVM区别不大,也是KKT 2 和线性回归的区别 对SVR,如果f(x)和y之间的差距小于阈值ε【也即落在两条间隔带之间】,则不计算…

华为交换配置OSPF与BFD联动

实验拓扑 组网需求 如图所示,SW1、SW2和SW3之间运行OSPF,SW1和SW2之间的交换机仅作透传功能。现在需要SW1和SW2能够快速感应它们之间的链路状态,当链路SW1-SW2发生故障时,业务能快速切换到备份链路SW1-SW3-SW2上 配置思路 采用…

QT isDirty函数

参考:QSqlTableModel 类 |Qt SQL 6.6.1

LeetCode 19 删除链表的倒数第 N 个结点

题目描述 删除链表的倒数第 N 个结点 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5]示例 2: 输入:head [1], n 1…

Flink cdc3.0同步实例(动态变更表结构、分库分表同步)

文章目录 前言准备flink环境docker构建mysql、doris环境数据准备 通过 FlinkCDC cli 提交任务整库同步同步变更路由变更路由表结构不一致无法同步 结尾 前言 最近Flink CDC 3.0发布, 不仅提供基础的数据同步能力。schema 变更自动同步、整库同步、分库分表等增强功…

开发知识点-HTML/JavaScript

HTML/JavaScript xlinksvgviewBoxuse基础预热与语法基础知识js 如何运行页面适用js 及输出 面向对象抽奖功能 json 支持 字符串转数组数组转字符串数组元素删除长度0位添加一个元素// 表示在下标为1处添加一项tttarray.splice(1,0,ttt)//[123,ttt,456]// 数组是否包含某个元素a…

天猫数据分析(天猫查数据工具):2023年天猫平台假发行业市场销售数据分析报告

如今,由于人们工作和生活的压力较大,居民脱发问题严重,且脱发群体倾向于80后和90后,逐渐向低龄化发展。除脱发外,在颜值经济的背景下,人们越来越注重外貌和形象,假发作为一种改善发型的工具&…

MyBatis——MyBatis的原始Dao开发(了解)

MyBatis的原始Dao开发-了解 使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方式和Mapper接口代理开发方式。而现在主流的开发方式是接口代理开发方式,这种方式总体上更加简便。在之前的文章已经给大家介绍了基于代理方式的dao开发&#x…

Javascript 开发html网页读写IC卡源码

本示例使用设备&#xff1a; Android Linux RFID读写器NFC发卡器WEB可编程NDEF文本/智能海报/-淘宝网 (taobao.com) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">…