网络编程的学习初篇

previewfile_3005866398

网络原理初始

网络原理和网络编程[重要]
网络能够跨主机通信!
我们未来工作,很可能是成为后端开发工程师,写服务器,和客户端通信,肯定会涉及到网络.

网络初始

计算机网络的由来

~~ 计算机网络这是计科相关专业最核心的专业课!!!

计算机是咋来的??最初是用来计算弹道导弹的轨迹 => 为了打仗
计算机网络是咋来的?同理,也是打仗打出来的!!!
互联网之前,可以通过有线/无线,发电报,有电话.缺点非常明显,通信链路容易被打击.

二战之后 ~~ 美苏争霸,冷战
武器不停升级=>核武器, 杀伤力太大了 ~~ 使用核武器,妥妥的把你通信链路,连根拔起.
美国人开始研究,有没有办法,能够搞出一种通信手段,即使是核武器,也打击不了!!
古巴导弹危机
美国人开始在北约,部署核武器,能直接威胁到苏联本土
古巴离美国本土太近了,苏联人就准备在古巴,部署核武器,直接威胁到美国本土最后苏联放弃了,核战争没打起来.

上个世纪,80年代左右,网络还处在萌芽阶段.不过,有些学校/研究所,已经尝试把计算机进行相连,可以进行简单的网络通信了.
到了后来,这个时候,时代背景,冷战(局势是非常紧张的)

这个事情完了之后,大国就开始反思,
在这种核威慑下,如何才能保证足够的威慑力??
A和B相互威慑,意思就是A可以对B进行核打击.但是B在承受打击之后,仍然有能力进行反制(对A进行核打击)如果B的反击能够成立,此时意味着A和B之间谁都不敢轻举妄动.

A打击B要打击哪里?
1.政府核心机构 ~~ 重点目标,必然重点保护,想打掉没那么容易!!!
2.打击B的导弹发射井 ~~ 重点目标,必然重点保护 ~~ 想打掉没那么容易!!!
3.打击网络通信系统 => 假设A把B的网络系统打掉了,此时B想反制,肯定是政府核心机构,发起打击命令,由导弹发射井执行~~此时命令可能就传不过去了!!

因此,研究重点,就是研究出一种通信网络,不怕核打击!!!
在上述背景下,互联网,就应运而生了.

关键问题,万一真的受到核打击了,通信链路仍然正常,因此可以发出指令,进行核反击

image-20231017151656714

后来大家就发现了,互联网这个东西,民用更香!!!就衍生出了很多很多的公司和产品,构建成了咱们今天的丰富的互联网世界.
现在互联网已经渗透到生活中的方方面面了,国内的互联网兴起,得是从2000年左右开始算了.

网络编程

基于操作系统提供的socket api来进行网络数据的发送和接收,Java在JVM中又进行了封装.名字上还是叫做Socket,让内核中的传输层协议和咱们应用程序中应用层的协议进行相互通信.

传输层的主要协议: TCP ,UDP
UDP:无连接,不可靠传输,面向数据报,全双工
TCP:有连接,可靠传输,面向字节流,全双工
代码写的风格差别很大.

DatagramSocket: 代表着 socket 文件(操作系统操作网卡,也不是直接操作,而是把网卡抽象成了特殊的文件,称为 socket 文件).
对 UDP 来说,传输数据的基本单位,DatagramPacket指定一个字节数组,作为持有数据的缓冲区.
一次通信涉及到源IP,源端口,目的IP,目的端口,协议类型

死循环在服务器程序中没什么问题,生活中使用的大部分的程序的服务器都是7 * 24小时的.
当然,有的服务器比较牛,不是 7 * 24小时运行…典型代表: 12306 23:00->6:00进行维护

UDP版本的回显服务器

部分相关代码

package network;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-17* Time: 19:22*/// UDP 版本的回显服务器
public class UdpEchoServer {// 网络编程,本质上是要操作网卡// 但是网卡不方便直接操作,在操作系统内核中,使用了一种特殊的叫做 "socket" 这样的文件来抽象表示网卡// 因此进行网络通信,势必需要有一个 socketprivate DatagramSocket socket = null;// 对于服务器来说,创建 socket 对象的同时,要让他绑上一个具体的端口号// 服务器一定要关联上一个具体的端口// 服务器是网络传输中,被动的一方,如果是操作系统随机分配的端口,此时客户端就不知道这个端口是什么了,也就无法进行通信了.public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");// 服务器不是只给一个客户端提供服务,需要服务很多客服端while (true) {// 只要有客户端过来,就可以提供服务// 1. 读取客户端发送的请求//    receive方法的参数是一个输出型参数,//    需要先构造好个空白的 DatagramPacket 对象, 交给 receive 来进行填充.DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// receive内部会针对参数对象填充数据,填充的数据来自于网卡.// 此时这个 DatagramPacket 是一个特殊的对象,并不方便直接进行处理,可以把这里包含的数据拿出来,构造成一个字符串String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求计算响应,由于是回显服务器,请求和响应相同.String response = process(request);// 3. 把响应数据写回到客户端, send 的参数也是 DatagramPacket,需要把这个 Packet 对象构造好.//    此处构造的响应对象,不能是用空的字节数组构造了,而是要使用响应数据来构造.DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress());socket.send(responsePacket);}}// 这个方法就表示"根据请求计算响应"private String process(String request) {return request;}
}

image-20231018195246690

代码的注解

image-20231018204629510

image-20231018225532796

服务器的工作流程.
1.读取请求并解析
2.根据请求计算响应
3.构造响应并写回给客户端

客户端这边的代码

image-20231018235452114

注: 端口号用来标识/区分一个进程.因此在同一个主机上,不允许一个端口同时被多个进程使用.
不过,一个进程可以绑定多个端口,进程只要创建多个 socket 对象,就可以分别关联不同的端口.
总结: socket 和 端口号是一对一的,进程和 socket 是一对多的.

对于服务器,端口必须是确定好的,对于客户端来说,端口可以是系统分配的.
虽然客户端可以做到指定端口号,但是不推荐!!! 因为客户端如果显示指定端口,可能就和客户端电脑上的其他程序的端口冲突了,这一冲突就可能导致程序无法正确通信了(运行就会抛出异常,提示绑定端口失败).

问题来了: 为什么服务器这里指定端口就不怕重复呢?
服务器是我们程序猿自己手里的机器,上面运行啥,都是可控的.我们可以安排哪个程序用哪个端口[可控的]
客户端的机器是在用户手里的,不同用户手里的机器,种类繁多,上面运行着哪些程序,也各有不同[不可控]

总结: 服务器的端口是要固定指定的,目的是为了方便客户端找到服务器程序.
客户端的端口是由系统自动分配的,如果手动指定,可能会和客户端其他程序的端口冲突.
服务器不怕冲突的原因,因为服务器上面的程序可控.客户端是运行在用户电脑上,环境更复杂,更不可控.

image-20231019145332507

image-20231020143755379

我们看到的IP地址: 127.0.0.1 => 32位的整数(给计算机看的).
点分十进制(给人看的),每个部分,范围是 0-255 一个字节.

DatagramSocket这个类的receive能阻塞,是因为操作系统原生提供的APl (recv)就是阻塞的函数.
这里的阻塞不是Java 实现的,而是系统内核里实现的.
系统里对于IO操作本身就有这样阻塞等待的机制.
哪个线程如果进行IO操作,在IO完成之前,就会自动把对应的线程放到阻塞队列中,暂时不参与调度.

对于客户端服务器程序来说一个服务器要给很多客户端提供服务的,我们也就需要构造出多个客户端来进行测试.
由于 IDEA 默认只能启动一个客户端所以需要稍微调整一下,让idea 能启动多个客户端.

image-20231020153722524

修改后的运行结果展示

image-20231020154126177

注: 当前的客户端和服务器程序,都是在博主自己的笔记本上跑的,而实际上,网络存在的意义,是跨主机通信的.
但是如果我把客户端的代码发给别人,别人是连不上我笔记本上的服务器程序的.
但是有解决办法: 让其他人连上“云服务器”这样的特殊电脑,“云服务器”有外网 IP,任何一个连上网络的设备都能访问(博主的笔记本电脑是没有外网IP,只能在局域网内部访问,所以别人是连不上我笔记本上的服务器程序的)

把程序部署到云服务器(了解即可)
1.把java程序打包.
image-20231020220421283

image-20231020220955618

image-20231020221628095

上述操作的结果

image-20231020222230078

2.对云服务器(Linux系统)相关操作

image-20231020230510912

将IP地址更改为云服务器的IP

image-20231020230417535

image-20231020230528463

博主的笔记本电脑和云服务器(另一个主机)跨越网络进行通讯了.
注: 可以把代码发给其他人,这样你们观看云服务器上的你们发送的信息进行交流了.
image-20231020231559564

相关的完整代码

UdpEchoClient.java
import java.io.IOException;
import java.net.*;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-17* Time: 19:23*/// UDP 版本的 回显客户端
public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp = null;private int serverPort = 0;// 一次通信,需要有两个ip,两个端口// 此时客户端的 ip 是 127.0.0.1 已知的// 客户端的 port 是系统自动分配的// 服务器 ip 和 端口 也需要告诉客户端,才能顺利把消息发到服务器public UdpEchoClient(String serverIp, int serverPort) throws SocketException {socket = new DatagramSocket();this.serverIp = serverIp;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);while (true) {// 1.从控制台读取数据System.out.print("> ");String request = scanner.next();if (request.equals("exit")) {System.out.println("goodbye");break;}// 2. 构造成 UDP 请求//    构造这个 Packet 的时候,需要把 serverIP 和 port 都传入过来,但是此处 IP 地址需要填写的是一个 32 位的整数形式.//    上述的 IP 地址是一个字符串,需要使用 InetAddress.getByName 来进行一个转换.DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 3.读取服务器的 UDP 响应, 并解析DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);String response = new String(responsePacket.getData(),0,responsePacket.getLength(),"utf8");// 4. 把解析好的结果显示出来System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);client.start();}
}
UdpEchoServer.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-17* Time: 19:22*/// UDP 版本的回显服务器
public class UdpEchoServer {// 网络编程,本质上是要操作网卡// 但是网卡不方便直接操作,在操作系统内核中,使用了一种特殊的叫做 "socket" 这样的文件来抽象表示网卡// 因此进行网络通信,势必需要有一个 socketprivate DatagramSocket socket = null;// 对于服务器来说,创建 socket 对象的同时,要让他绑上一个具体的端口号// 服务器一定要关联上一个具体的端口// 服务器是网络传输中,被动的一方,如果是操作系统随机分配的端口,此时客户端就不知道这个端口是什么了,也就无法进行通信了.public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");// 服务器不是只给一个客户端提供服务,需要服务很多客服端while (true) {// 只要有客户端过来,就可以提供服务// 1. 读取客户端发送的请求//    receive方法的参数是一个输出型参数,//    需要先构造好个空白的 DatagramPacket 对象, 交给 receive 来进行填充.DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// receive内部会针对参数对象填充数据,填充的数据来自于网卡.// 此时这个 DatagramPacket 是一个特殊的对象,并不方便直接进行处理,可以把这里包含的数据拿出来,构造成一个字符串String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求计算响应,由于是回显服务器,请求和响应相同.String response = process(request);// 3. 把响应数据写回到客户端, send 的参数也是 DatagramPacket,需要把这个 Packet 对象构造好.//    此处构造的响应对象,不能是用空的字节数组构造了,而是要使用响应数据来构造.DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress());socket.send(responsePacket);// 4. 打印一下, 当前这次请求响应的处理中间结果System.out.printf("[%s:%d] req: %s; resp: %s\n",requestPacket.getAddress().toString()/*获取到packet里面的ip*/,requestPacket.getPort()/*获取到里面的端口*/,request,response);}}// 这个方法就表示"根据请求计算响应"private String process(String request) {return request;}public static void main(String[] args) throws IOException {// 端口号的指定,可以随便指定// 1024 -> 65535 这个范围里随便挑个数字就行了UdpEchoServer server=new UdpEchoServer(9090);server.start();}
}

实现一个简单的翻译程序

回显服务器,缺少业务逻辑
就在上述代码的基础上稍作调整,就可以实现一个“查词典”的服务器(英文单词,翻译成中文解释).
注: 代码主要是复用了之前 EchoServer 的代码,然后重写 process 就行了.

不同的服务器,对应的服务器是不同的,因此,处理的流程就是不同的,对于一些复杂的服务器, process 里面可能要运行几万行,几十万行……

UdpDictServer.java

import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-21* Time: 0:01*/// 对于 DictServer 来说, 和 EchoServer 相比,大部分的东西都是一样的.
// 主要是 "根据请求计算响应" 这个步骤不太一样.
public class UdpDictServer extends UdpEchoServer {private Map<String, String> dict = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);// 给这个 dict 设置内容dict.put("cat", "小猫");dict.put("dog", "小狗");dict.put("fly", "廖飞洋");// 当然,这里可以无限多的设置键值对......}@Overridepublic String process(String request) {// 查词典的过程return dict.getOrDefault(request, "当前单词没有查到结果!");}
}

运行结果

image-20231021113620823

端口冲突

一个端口只能被一个进程使用,如果有多个使用,就不被允许.

image-20231021125147691

Address already in use: Cannot bind
这里的 bind 是操作系统原生的API,这个API本身就是起到的“绑定IP+端口”,Address 表示的含义就相当于“IP+端口”.

TCP的相关 API 的使用

TCP提供的API主要是两个类:
ServerSocket专门给服务器使用的Socket对象
Socket是既会给客户端使用,也会给服务器使用

TCP不需要一个类来表示“TCP数据报”,因为TCP不是以数据报为单位进行传输的,是以字节的方式,进行流式传输.

ServerSocket API

~~ ServerSocket 是创建TCP服务端Socket的API

ServerSocket 构造方法

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket 对象,并基于该Socket建立与客户端的连接,否则阻塞等待相当于“接电话”,接了电话,会返回一个Socket对象,通过这个Socket对象和客户端进行沟通.
void close()关闭此套接字

Socket API

在服务器这边,是由accept返回的,在客户端这边,是由我们代码里构造的,构造的时候指定一个IP和端口号(此处的IP和端口号是服务器的IP和端口),有了这个信息,就能够和服务器建立连接了.

Socket 构造方法

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入
OutputStream getOutputStream()返回此套接字的输出流

InputStream getInputStream(),OutputStream getOutputStream():进一步通过Socket对象,获取到内部的流对象,借助流对象进行发送/接受.

TCP版本的回显服务器

相关代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-21* Time: 15:26*/
public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");while (true) {/* accept效果是"接收连接",前提是得有客户端来建立连接!客户端在构造Socket对象的时候,就会指定服务器的IP和端口.如果没有客户端来连接,此时accept就会阻塞.*/Socket clientSocket = serverSocket.accept();// 使用这个 clientSocket和具体的客户端进行交流.processConnection(clientSocket);}}// 使用这个方法来处理一个连接// 这一个连接对应到一个客户端,但是这里可能会涉及到多次交互private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());// 基于上述 socket 对象和客户端进行通信try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream()) {// 由于要处理多个请求和响应,也是使用循环来进行的while (true){// 1.读取请求Scanner scanner = new Scanner(inputStream);if (!scanner.hasNext()){// 没有下一个数据,说明读完了(客户端关闭了连接)System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}// 注: 此处使用 next 是一直读取到换行符/空格/其他空白符结束,但是最终返回结果里不包含上述空白符.String request=scanner.next();// 2.根据请求构造响应String response=process(request);// 3.返回响应结果// outputStream 没有 write String 这样的功能,可以把 String 里的字节数组拿出来,进行写入PrintWriter printWriter=new PrintWriter(outputStream);// 此处使用 println 来写入,让结果中带有一个 \n,方便接受端来接受解析printWriter.println(response);// flush 用来刷新缓冲区,保证当前写入的数据,确实是发送出去了.printWriter.flush();System.out.printf("[%s %d] req: %s; resp: %s \n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}}catch (IOException e){e.printStackTrace();}finally {// 把 close 放到 finally 里面的,保证一定你能执行到!clientSocket.close();}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server=new TcpEchoServer(9090);server.start();}
}

image-20231021193510005
Socket clientSocket = serverSocket.accept();
processConnection(clientSocket);
这个代码中,用到一个clientSocket.此时任意一个客户端连上来,都会返回/创建一个Socket对象.(Socket就是文件)每次创建一个clientSocket对象,就要占用一个文件描述符表的位置.再加上因为每个客户端都有一个,此处的clientSocket的数量就会非常多,因此在使用完毕之后,就需要进行"释放".

代码缺陷: 当前的这个TCP server 有一个致命缺陷,一次只能处理一个客户端.

主要是主动发起请求的一方,就是服务器.只要是被动的一方,就是服务器.所以一个服务器即可是服务器,也可以是客户端.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-21* Time: 18:48*/
public class TcpEchoClient {private Socket socket=null;public TcpEchoClient(String serverIp,int serverPort) throws IOException {// Socket 构造方法,能够识别 点分十进制格式的IP地址,比DatagramPacket更方便.// new 这个对象的同时,就会进行 TCP 的连接操作.socket=new Socket(serverIp,serverPort);}public void start(){System.out.println("客户端启动!");Scanner scanner=new Scanner(System.in);try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()) {while (true){// 1.先从键盘读取用户输入的内容System.out.println(">");String request=scanner.next();if (request.equals("exit")){System.out.println("goodbye");break;}// 2.把读到的内容构造成请求,发送到服务器PrintWriter printWriter=new PrintWriter(outputStream);printWriter.println(request);// 此处加个 flush,保证数据确实发送printWriter.flush();// 3.读取服务器的响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();// 4.把响应内容显示到界面上System.out.println(response);}} catch (Exception e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);client.start();}
}

image-20231021200751756

运行结果

image-20231021200922413

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

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

相关文章

Kubernetes技术与架构-Ingress Controller

Ingress Controller控制器是实现Ingress对象的定义的组件&#xff0c;也即网关&#xff0c;负责Kubernetes集群内流量的分发&#xff0c;Kubernetes可以运行多个Ingress Controller控制器实例&#xff0c;不同的Ingress定义可以使用不同的Ingress Controller控制器实现&#xf…

搞个微信小程序002:个人信息

新建一个用于&#xff0c;和001中一样&#xff0c;然后&#xff0c;就改掉两个文件&#xff1a; index.wxml: <view><!-- 头像区域 --><view class"top"><view class"user-img"><image src"/images/tx.png"><…

PostgreSQL 插件 CREATE EXTENSION 原理

PostgreSQL 提供了丰富的数据库内核编程接口&#xff0c;允许开发者在不修改任何 Postgres 核心代码的情况下以插件的形式将自己的代码融入内核&#xff0c;扩展数据库功能。本文探究了 PostgreSQL 插件的一般源码组成&#xff0c;梳理插件的源码内容和实现方式&#xff1b;并介…

mybatis写sql

批量查询 <select id"getPreIds" resultType"java.lang.String"parameterType"java.util.List">SELECT pre_batch_id FROM public.mine_data_quality_check_record WHERE deleted0<if test"list ! null">AND pre_batch…

codeshell安装配置

codeshell安装配置 1 注意事项1.1 Python版本问题 2 codeshell环境搭建2.1 codeshell使用软件各版本2.2 软件下载2.3 codeshell使用环境安装2.3.1 python-3.10.9-amd64.exe安装2.3.2 Anaconda3-2022.10-Windows-x86_64.exe安装2.3.3 创建环境2.3.4 Pytorch安装2.3.5 transforme…

C++初阶 入门(2)

目录 一、缺省函数 1.1什么是缺省函数 1.2为什么要有缺省函数 1.3使用缺省函数 1.4测试代码 二、函数重载 2.1什么是函数重载 2.2为什么要有函数重载 2.3什么情况构成函数重载 2.4函数重载例子及代码 三、引用 3.1什么是引用 3.2如何引用 ​3.3常引用(可略过) 3…

CCF CSP认证历年题目自练Day38

题目 试题编号&#xff1a; 201409-3 试题名称&#xff1a; 字符串匹配 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   给出一个字符串和多行文字&#xff0c;在这些文字中找到字符串出现的那些行。你的程序还需支持大小写敏感…

酒类商城小程序怎么做

随着互联网的快速发展&#xff0c;线上购物越来越普及。酒类商品也慢慢转向线上销售&#xff0c;如何搭建一个属于自己的酒类小程序商城呢&#xff1f;下面就让我们一起来看看吧&#xff01; 一、登录乔拓云平台 首先&#xff0c;我们需要进入乔拓云平台的后台&#xff0c;点击…

《向量数据库》——Zilliz X Dify.AI ,快速打造知识库 AI 应用

Zilliz 大模型生态矩阵再迎新伙伴!近日,Zilliz 和 Dify.AI 达成合作,Zilliz 旗下的产品 Zilliz Cloud、Milvus 与开源 LLMOps 平台 Dify 社区版进行了深度集成。 01. Zilliz Cloud v.s. Dify Dify 作为开源的 LLMs App 技术栈,在此前已支持丰富多元的大型语言模型的接入,…

【React Router】React Router学习笔记

React Router学习笔记 React Router1.什么是React Router?2.为什么要用React Router?3.基础3.1 路由配置3.2 路由匹配原理3.3 History3.3.1 browerHistory3.3.2 hashHistory3.3.3 createMemoryHistory3.3.4 实现示例 3.4 默认路由(IndexRoute)与IndexLink3.4.1 IndexRoute3.4…

[SQL开发笔记]WHERE子句 : 用于提取满足指定条件的记录

SELECT DISTINCT语句用户返回列表的唯一值&#xff1a;这是一个很特定的条件&#xff0c;假设我需要考虑很多中限制条件进行查询呢&#xff1f;这时我们就可以使用WHERE子句进行条件的限定 一、功能描述&#xff1a; WHERE子句用于提取满足指定条件的记录&#xff1b; 二、WH…

报错解决:libcudart.so和libprotobuf.so链接库未找到

报错解决&#xff1a;libcudart.so和libprotobuf.so链接库未找到 libcudart.so链接库未找到原因解决方法 libprotobuf.so链接库未找到原因解决方法 此博客介绍了博主在编译软件包时遇到的两个报错&#xff0c;主要是libcudart和libprotobuf两个动态链接库未找到的问题&#xff…

Nginx安装配置项目部署然后加SSL

个人操作笔记记录 第一步&#xff1a;把 nginx 的源码包nginx-1.8.0.tar.gz上传到 linux 系统 第二步&#xff1a;解压缩 tar zxvf nginx-1.8.0.tar.gz 第三步&#xff1a;进入nginx-1.8.0目录 使用 configure 命令创建一 makeFile 文件。 直接复制过去运行 ./configur…

【RocketMQ系列十二】RocketMQ集群核心概念之主从复制生产者负载均衡策略消费者负载均衡策略

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

KingBase库模式表空间和客户端认证(kylin)

库、模式、表空间 数据库 数据库基集簇与数据库实例 KES集簇是由单个KES实例管理的数据库的集合KES集簇中的库使用相同的全局配置文件和监听端口、共享相关的进程和内存结构同一数据库集簇中的进程、相关的内存结构统称为实例 数据库 数据库是一个长期存储在计算机内的、有…

【Tensorflow 2.12 简单智能商城商品推荐系统搭建】

Tensorflow 2.12 简单智能商城商品推荐系统搭建 前言架构数据召回排序部署调用结尾 前言 基于 Tensorflow 2.12 搭建一个简单的智能商城商品推荐系统demo~ 主要包含6个部分&#xff0c;首先是简单介绍系统架构&#xff0c;接着是训练数据收集、处理&#xff0c;然后是召回模型、…

redis分布式锁的应用

redis 作为分布式锁的东西 分布式锁的应用 redis,zk,数据库这些都可以实现分布式锁 我们今天主要基于redis实现的分布式锁&#xff0c;而且要求性能要好 基于一个小的业务场景来说&#xff0c;就比如说秒杀中的减库存&#xff0c;防止超卖这种代码就会有并发问题,比方说3个线程…

uni-app开发

uni-app 官方手册&#xff1a;uni-app官网 一&#xff1a;tarBar&#xff1a;一级导航栏&#xff0c;即 tab 切换时显示对应页。 在pages.json文件里写入如下代码&#xff1a; 此效果&#xff1a;

编译工具链 之一 基本概念、组成部分、编译过程、命名规则

编译工具链将程序源代码翻译成可以在计算机上运行的可执行程序。编译过程是由一系列的步骤组成的&#xff0c;每一个步骤都有一个对应的工具。这些工具紧密地工作在一起&#xff0c;前一个工具的输出是后一个工具的输入&#xff0c;像一根链条一样&#xff0c;我们称这一系列工…

Unity 单例-接口模式

单例-接口模式 使用接口方式实现的单例可以继承其它类&#xff0c;更加方便 using System.Collections; using System.Collections.Generic; using UniRx; using UniRx.Triggers; using UnityEngine; namespace ZYF {public interface ISingleton<TMono> where TMono : M…