Java分别用BIO、NIO实现简单的客户端服务器通信
分别用BIO、NIO实现客户端服务器通信
- BIO
- NIO
- NIO演示(无Selector)
- NIO演示(Selector)
前言:
Java I/O模型发展以及Netty网络模型的设计思想
BIO
Java BIO是Java平台上的BIO(Blocking I/O)模型,是Java中用于实现同步阻塞网络编程的一种方式。 在Java中,使用BIO模型需要通过Socket和ServerSocket类来完成网络连接和数据传输,但是由于BIO是同步阻塞的,所以会导致线程阻塞和资源浪费的问题。
因此,在高并发的网络编程场景中,通常会选择使用NIO(Non-blocking I/O)模型或者Netty等框架来实现。
服务端类代码
package com.yu.io.bio;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class BIOServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8081);while (true) {System.out.println("wait connect...");Socket clientSocket = serverSocket.accept();System.out.println(clientSocket.getPort() + "connected");System.out.println("start read...");byte[] readArr = new byte[1024];int read = clientSocket.getInputStream().read(readArr);if (read != -1) {System.out.println("read info : " + new String(readArr,0,read));}System.out.println("end read...");byte[] resBytes = "server response".getBytes();clientSocket.getOutputStream().write(resBytes);System.out.println("response info : " + new String(readArr,0,read));clientSocket.getOutputStream().flush();}}
}
客户端类代码
package com.yu.io.bio;import java.io.IOException;
import java.net.Socket;public class BIOClient {public static void main(String[] args) throws IOException {Socket clientSocket = new Socket("127.0.0.1",8081);byte[] resBytes = "client response".getBytes();clientSocket.getOutputStream().write(resBytes);System.out.println("response info : " + new String(resBytes));clientSocket.getOutputStream().flush();byte[] readArr = new byte[1024];int read = clientSocket.getInputStream().read(readArr);if (read != -1) {System.out.println("read info : " + new String(readArr,0,read));}}
}
NIO
Java NIO 能够支持非阻塞网络编程,可以理解为new io 或者no blok io 我更喜欢称之为new io,因为他不仅仅实现了非阻塞的网络编程方式,同时也封装了常用的网络编程api,更重要的是引入了多路复用器Selector的概念
下面的代码只是展示NIO非阻塞的实现,并没有展示NIO的真正用法
NIO演示(无Selector)
服务端类代码
package com.yu.io.nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;public class NIOServer {public static List<SocketChannel> socketChannelList = new ArrayList<>();public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8081));serverSocketChannel.configureBlocking(false);System.out.println("server start...");while (true) {SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel != null) {System.out.println(socketChannel.socket().getPort() + " connected");socketChannel.configureBlocking(false);socketChannelList.add(socketChannel);}List<SocketChannel> rmChannelList = new ArrayList<>();for (SocketChannel channel : socketChannelList) {try {doChannel(rmChannelList, channel);} catch (IOException ioException) {//有客户端断开连接System.out.println(channel.socket().getPort() + " disconnected");channel.close();rmChannelList.add(channel);}}socketChannelList.removeAll(rmChannelList);}}private static void doChannel(List<SocketChannel> rmChannelList, SocketChannel channel) throws IOException {ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = new String(readByteBuffer.array());if (read > 0) {System.out.println(channel.socket().getPort() + " : " + readStr);if (readStr.contains("hello")) {ByteBuffer sendByteBuffer = ByteBuffer.wrap("hello! I am robot.".getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}if (readStr.contains("old")) {ByteBuffer sendByteBuffer = ByteBuffer.wrap("I am 1 years old.".getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}if (readStr.contains("bey")) {ByteBuffer sendByteBuffer = ByteBuffer.wrap("see you.".getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}}if (read == -1) {rmChannelList.add(channel);}}
}
客户端类代码
package com.yu.io.nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;public class NIOClient {public static void main(String[] args) throws IOException {SocketChannel clientSocketChannel = SocketChannel.open();clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",8081));clientSocketChannel.configureBlocking(false);String sendStr = "hello! I am client " + clientSocketChannel.socket().getPort() + ".";ByteBuffer sendByteBuffer = ByteBuffer.wrap(sendStr.getBytes());clientSocketChannel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));int msgSize = 0;while (msgSize < 10) {ByteBuffer readByteBuffer = ByteBuffer.allocate(1024);int read = clientSocketChannel.read(readByteBuffer);String readStr = new String(readByteBuffer.array());if (read > 0) {System.out.println("robot : " + readStr);msgSize ++;ByteBuffer resByteBuffer = null;if (readStr.contains("hello")) {resByteBuffer = ByteBuffer.wrap("how old are you?.".getBytes());clientSocketChannel.write(resByteBuffer);System.out.println("me : " + new String(resByteBuffer.array()));resByteBuffer.clear();}if (readStr.contains("old")) {resByteBuffer = ByteBuffer.wrap("en, place say hello!".getBytes());clientSocketChannel.write(resByteBuffer);System.out.println("me : " + new String(resByteBuffer.array()));resByteBuffer.clear();}}}ByteBuffer resByteBuffer = ByteBuffer.wrap("bey bey!".getBytes());clientSocketChannel.write(resByteBuffer);System.out.println("me : " + new String(resByteBuffer.array()));resByteBuffer.clear();clientSocketChannel.close();}
}
NIO演示(Selector)
无Selector的NIO演示中,显然会出现空转的情况,以及无效连接的处理问题,这些问题都会影响性能。
NIO提供Selector多路复用器,优化上述问题
以下demo实现服务器与客户端通信,相互发消息。并由服务器转发给其他客户端(广播功能)
服务端类代码
server main类
import java.io.IOException;public class NIOServerMain {public static void main(String[] args) throws IOException {NIOSelectorServer server = new NIOSelectorServer();server.start();}
}
server run类
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;public class NIOSelectorServer {public void start() throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8081));serverSocketChannel.configureBlocking(false);//注册到selector多路复用器中Selector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("server start...");run(selector);}/*** 遍历多路复用器的事件,处理事件*/private void run(Selector selector) throws IOException {while (true) {//阻塞等待事件selector.select();Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey selectedKey = iterator.next();try {if (selectedKey.isAcceptable()) {doAccept(selector, selectedKey);}if (selectedKey.isReadable()) {doReadChannel(selectedKey, selector);}} catch (IOException ioException) {//有客户端断开连接disConnect(selectedKey, "exception");}iterator.remove();}}}/*** 处理连接事件*/private void doAccept(Selector selector, SelectionKey selectedKey) throws IOException {ServerSocketChannel serverChannel = (ServerSocketChannel)selectedKey.channel();SocketChannel socketChannel = serverChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);System.out.println(socketChannel.socket().getPort() + " connected");}/*** 处理接收信息事件*/private void doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = "";readByteBuffer.flip();readStr += StandardCharsets.UTF_8.decode(readByteBuffer);if (read > 0) {System.out.println(channel.socket().getPort() + " : " + readStr.length() + " - "+ readStr);//转发消息(其他客户端)broadcast(selectedKey, selector, readStr);if (readStr.contains("hello")) {sendMsg(channel, "hello! I am robot.");}if (readStr.contains("old")) {sendMsg(channel, "I am 1 years old.");}if (readStr.contains("bye")) {sendMsg(channel, "see you.");}}if (read == -1) {//有客户端断开连接disConnect(selectedKey, "read = -1");}}/*** 连接异常的处理*/private void disConnect(SelectionKey selectedKey, String type) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();System.out.println(channel.socket().getPort() + " disconnected. " + type);selectedKey.cancel();channel.close();}/*** 发送消息*/private void sendMsg(SocketChannel channel, String s) throws IOException {ByteBuffer sendByteBuffer = ByteBuffer.wrap(s.getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}/*** 广播* 转发消息(给其他客户端)*/private void broadcast(SelectionKey fromSelectedKey, Selector selector, String readStr) throws IOException {Iterator<SelectionKey> selectionKeyIterator = selector.keys().iterator();while (selectionKeyIterator.hasNext()) {SelectionKey otherKey = selectionKeyIterator.next();if (otherKey == fromSelectedKey) {continue;}if (!(otherKey.channel() instanceof SocketChannel)) {continue;}SocketChannel otherChannel = (SocketChannel)otherKey.channel();sendMsg(otherChannel, "(转发自 "+ ((SocketChannel)fromSelectedKey.channel()).socket().getPort() + ")" + readStr);}}
}
客户端代码
一共构造了两个客户端(消息客户端和looker客户端), looker客户端优先启动,随后启动消息客户端,消息客户端与服务器的通信会被转发给looker客户端
look client main类
import java.io.IOException;public class NIOClientLookMain {public static void main(String[] args) throws IOException, InterruptedException {NIOSelectorClient client = new NIOSelectorLookClient();client.start(8081, 100);}
}
msg client main类
import java.io.IOException;public class NIOClientMain {public static void main(String[] args) throws IOException, InterruptedException {NIOSelectorClient lookClient = new NIOSelectorClient();lookClient.start(8081, 10);}
}
client run类
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;public class NIOSelectorClient {protected int port;protected int size;public void start(int port, int size) throws IOException, InterruptedException {this.port = port;this.size = size;SocketChannel clientSocketChannel = SocketChannel.open();clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",port));clientSocketChannel.configureBlocking(false);Selector selector = Selector.open();clientSocketChannel.register(selector, SelectionKey.OP_READ);//发送开始数据sendMsg(clientSocketChannel, "hello! I am client " + clientSocketChannel.socket().getLocalPort() + ".");run(selector);sendMsg(clientSocketChannel, "bye bye!");clientSocketChannel.close();}/*** 遍历多路复用器的事件,处理事件*/protected void run(Selector selector) throws IOException, InterruptedException {int msgSize = 0;while (msgSize < size) {int length=selector.select();if(length ==0){continue;}Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while(iterator.hasNext()){SelectionKey selectionKey = iterator.next();if(selectionKey.isReadable()){boolean readChannel = false;try {readChannel = doReadChannel(selectionKey, selector);} catch (IOException e) {selectionKey.cancel();System.out.println("robot disconnect, restart connect...");while (true){try {reConnect();return;} catch (IOException ioException) {System.out.println("restart connecting(5s) ");//ioException.printStackTrace();Thread.sleep(5000);}}}if (readChannel) {msgSize ++;}}iterator.remove();}}}protected boolean doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = "";readByteBuffer.flip();readStr += StandardCharsets.UTF_8.decode(readByteBuffer);if (read > 0) {System.out.println("robot : " + readStr);if (readStr.contains("hello")) {sendMsg(channel, "how old are you?.");}if (readStr.contains("old")) {sendMsg(channel, "en, place say hello!");}return true;}return false;}protected void sendMsg(SocketChannel channel, String sendStr) throws IOException {ByteBuffer sendByteBuffer = ByteBuffer.wrap(sendStr.getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}protected void reConnect() throws IOException, InterruptedException {NIOSelectorClient client = new NIOSelectorClient();client.start(port, size);}
}
look client run类
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;public class NIOSelectorLookClient extends NIOSelectorClient{@Overridepublic void start(int port, int size) throws IOException, InterruptedException {this.port = port;this.size = size;SocketChannel clientSocketChannel = SocketChannel.open();clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",port));clientSocketChannel.configureBlocking(false);Selector selector = Selector.open();clientSocketChannel.register(selector, SelectionKey.OP_READ);//发送开始数据sendMsg(clientSocketChannel, "I am looker. " + clientSocketChannel.socket().getLocalPort() + ".");run(selector);}@Overrideprotected boolean doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = "";readByteBuffer.flip();readStr += StandardCharsets.UTF_8.decode(readByteBuffer);if (read > 0) {System.out.println("robot : " + readStr.length() + " - "+ readStr);if (readStr.contains("bye")) {sendMsg(channel, "bye.");}return true;}return false;}@Overrideprotected void reConnect() throws IOException, InterruptedException {NIOSelectorClient client = new NIOSelectorLookClient();client.start(port, size);}
}
相关文章:

Java分别用BIO、NIO实现简单的客户端服务器通信
分别用BIO、NIO实现客户端服务器通信 BIONIONIO演示(无Selector)NIO演示(Selector) 前言: Java I/O模型发展以及Netty网络模型的设计思想 BIO Java BIO是Java平台上的BIO(Blocking I/O)模型&a…...
React Portals
什么是React Portals React Portals(React 门户)是 React 提供的一种机制,用于将组件渲染到 DOM 树中的不同位置,而不受组件层次结构的限制。它允许你将一个组件的渲染内容“传送”到 DOM 结构中的任何位置,通常用于处…...

Python基础之高级函数
异常捕获 Python中,使用trycatch两个关键字来实现对异常的处理。在我们平时的工作中,异常的出现是在所难免的,但是异常一旦出现,极有可能会直接导致程序崩溃,无法正常运行,所以异常一定要及时的做出对应的…...

CSS3常用的新功能总结
CSS3常用的新功能包括圆角、阴渐变、2D变换、3D旋转、动画、viewpor和媒体查询。 圆角、阴影 border-redius 对一个元素实现圆角效果,是通过border-redius完成的。属性为两种方式: 一个属性值,表示设置所有四个角的半径为相同值ÿ…...

Lvs+KeepAlived高可用高性能负载均衡
目录 1.环境介绍 2.配置keepalived 3.测试 1.测试负载均衡 2.测试RS高可用 3.测试LVS高可用 3.1测试lvs主服务宕机 3.2.测试lvs主服务器恢复 4.我在实验中遇到的错误 1.环境介绍 环境:centos7 RS1---RIP1:192.168.163.145 VIP 192.168.163.200 RS2---RIP2…...

无涯教程-Android Online Test函数
Android在线测试模拟了真正的在线认证考试。您将看到基于 Android概念的多项选择题(MCQ),将为您提供四个options。您将为该问题选择最合适的答案,然后继续进行下一个问题,而不会浪费时间。完成完整的考试后,您将获得在线考试分数。 总问题数-20 最长时间-20分钟 Start Test …...

蓝桥杯打卡Day1
文章目录 全排列八皇后 一、全排列IO链接 本题思路:本题是一道经典的全排列问题,深度优先搜索即可解决。 #include <bits/stdc.h>constexpr int N10;std::string s; std::string ans; int n; bool st[N];void dfs(int u) {if(un){std::cout<<ans<…...
zipkin2.24.2源码install遇见的问题
1、idea导入项目后将Setting中的关于Maven和Java Compile相关的配置改为jdk11,同时Project Structure改为jdk11 2、将pom配置中的fork标签注释 标题未修改以上配置产生的问题 Compilation failure javac: Ч ı : --release : javac <options> <source files&g…...

yapi密码是如何生成的
yapi密码是如何生成的 关闭yapi注册功能后,想要通过手动插入用户数据到db中,那么密码是如何生成的呢? exports.generatePassword (password, passsalt) > { return sha1(password sha1(passsalt)); }; 所以如果想要创建一个用户&#x…...

2023-09-02 LeetCode每日一题(最多可以摧毁的敌人城堡数目)
2023-09-02每日一题 一、题目编号 2511. 最多可以摧毁的敌人城堡数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 n ,下标从 0 开始的整数数组 forts ,表示一些城堡。forts[i] 可以是 -1 ,0 或者 1 ,其中&…...

k8s环境部署配置
目录 一.虚拟机准备 二.基础环境配置(各个节点都做) 1.IP和hosts解析 2.防火墙和selinux 3.安装基本软件 4.配置时间同步 5.禁用swap分区 6.修改内核参数并重载 7.配置ipvs 三.docker环境(各个节点都做) 1.配置软件源并…...

Java之文件操作与IO
目录 一.认识文件 1.1文件是什么? 1.2文件的组织 1.3文件路径 1.4文件的分类 二.文件操作 2.1File概述 三.文件内容操作--IO 3.1JavaIO的认识 3.2Reader和Writer ⭐Reader类 ⭐Writer类 3.2FileInputStream和FileOutputStream ⭐FileInputStream类 …...

指令系统(408)
一、拓展操作码指令格式 【2017 统考】某计算机按字节编址,指令字长固定且只有两种指令格式,其中三地址指令29条、二地址指令107条,每个地址字段6位,则指令字长至少应该是( A) A、24位 B、26位 …...

Pygame中Trivia游戏解析6-3
3.3 Trivia类的show_question()函数 Trivia类的show_question()函数的作用是显示题目。主要包括显示题目框架、显示题目内容和显示题目选项等三部分。 3.3.1 显示题目的框架 在show_question()函数中,通过以下代码显示题目的框架。 print_text(font1, 210, 5, &q…...

热释电矢量传感器设计
1 概述 使用4个热释电传感器组成一个2X2的矩阵。通过曲线的相位差、 峰峰值等特征量来计算相关信息。本文使用STM32单片机设计、制作了热释电传感器矩阵;使用C#.NET设计了上位机软件。为以上研究做了试验平台。 2 硬件电路设计 2.1 热释电传感器介绍 热释电红外…...
MySql学习笔记10——视图介绍
视图 概述 view view可以看作是一张“虚拟表”,(但是他也是会作为文件存在的) 当我们通过复杂的查询语句获取一张表的时候,可以将这张表作为一个视图,和创建一个新表不同,在视图上进行的DML操作会对数据…...

【探索Linux】—— 强大的命令行工具 P.7(进程 · 进程的概念)
阅读导航 前言一、冯诺依曼体系结构二、操作系统(OS)1. 概念 三、进程1. 进程的概念2. PCB(Process Control Block)3. 查看进程 四、fork函数1. 函数简介2. 调用方式3. 返回值4. 使用示例 五、进程的几种状态1. 状态简介2. 进程状…...

JAVA宝典----容器(理解记忆)
目录 一、Java Collections框架是什么? 二、什么是迭代器? 三、Iterator与ListIterator有什么区别? 四、ArrayList、Vector和LinkedList有什么区别? 五、HashMap、Hashtable、TreeMap和WeakHashMap有哪些区别? 六…...
JS中的扩展操作符...(点点点)
标题 前言概述拓展操作符(Spread Operator)赋值与扩展操作符的区别 剩余操作符(Rest Operator) 前言 大家应该都在代码中用过或者看到…方法,我每次用到这个方法的时候都会想到第一次见到这个方法一头雾水的样子&#…...

找redis大key工具rdb_bigkeys
github官网 https://github.com/weiyanwei412/rdb_bigkeys 在centos下安装go [roothadoop102 rdb_bigkeys-master]# wget https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz [roothadoop102 rdb_bigkeys-master]# tar -zxf go1.13.5.linux-amd64.tar.gz -C /usr/local将g…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...

WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...

基于谷歌ADK的 智能产品推荐系统(2): 模块功能详解
在我的上一篇博客:基于谷歌ADK的 智能产品推荐系统(1): 功能简介-CSDN博客 中我们介绍了个性化购物 Agent 项目,该项目展示了一个强大的框架,旨在模拟和实现在线购物环境中的智能导购。它不仅仅是一个简单的聊天机器人,更是一个集…...

2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】
1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...

以太网PHY布局布线指南
1. 简介 对于以太网布局布线遵循以下准则很重要,因为这将有助于减少信号发射,最大程度地减少噪声,确保器件作用,最大程度地减少泄漏并提高信号质量。 2. PHY设计准则 2.1 DRC错误检查 首先检查DRC规则是否设置正确,然…...