Netty框架

article/2025/9/21 11:25:57

概述

Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠性的网络 IO 程序。

Netty 是一个基于 NIO 的网络编程框架,使用 Netty 可以帮助你快速、简单的开发出一个网络应用,相当于简化和流程化了 NIO 的开发过程。

作为当前最流行的 NIO 框架,Netty 在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,知名的 Elasticsearch 、Dubbo 框架内部都采用了 Netty。

 

Netty 整体设计

线程模型

单线程模型

 

服务器端用一个线程通过多路复用搞定所有的 IO 操作(包括连接,读、写等),编码简单,清晰明了,但是如果客户端连接数量较多,将无法支撑,咱们前面的 NIO 案例就属于这种模型。

线程池模型

 

服务器端采用一个线程专门处理客户端连接请求,采用一个线程池负责 IO 操作。在绝大多数场景下,该模型都能满足使用。

Netty 模型

 

比较类似于上面的线程池模型,Netty 抽象出两组线程池,BossGroup 专门负责接收客户端连接,WorkerGroup 专门负责网络读写操作。NioEventLoop 表示一个不断循环执行处理任务的线程,每个 NioEventLoop 都有一个 selector,用于监听绑定在其上的 socket 网络通道。NioEventLoop 内部采用串行化设计,从消息的读取->解码->处理->编码->发送,始终由 IO 线程 NioEventLoop 负责。

一个 NioEventLoopGroup 下包含多个 NioEventLoop
每个 NioEventLoop 中包含有一个 Selector,一个 taskQueue
每个 NioEventLoop 的 Selector 上可以注册监听多个 NioChannel
每个 NioChannel 只会绑定在唯一的 NioEventLoop 上
每个 NioChannel 都绑定有一个自己的 ChannelPipeline
 
异步模型

FUTURE,                                 CALLBACK                                  和               HANDLER Netty 的异步模型是建立在 future 和 callback 的之上的。callback 大家都比较熟悉了,这

里重点说说 Future,它的核心思想是:假设一个方法 fun,计算过程可能非常耗时,等待 fun 返回显然不合适。那么可以在调用 fun 的时候,立马返回一个 Future,后续可以通过 Future 去监控方法 fun 的处理过程。

在使用 Netty 进行编程时,拦截操作和转换出入站数据只需要您提供 callback 或利用future 即可。这使得链式操作简单、高效, 并有利于编写可重用的、通用的代码。Netty 框架的目标就是让你的业务逻辑从网络基础应用编码中分离出来、解脱出来。

 

核心 API

ChanneHandler 及其实现类

 

ChannelHandler 接口定义了许多事件处理的方法,我们可以通过重写这些方法去实现具体的业务逻辑。API 关系如下图所示:

 

我们经常需要自定义一个 Handler 类去继承 ChannelInboundHandlerAdapter,然后通过重写相应方法实现业务逻辑,我们接下来看看一般都需要重写哪些方法:

public void channelActive(ChannelHandlerContext ctx),通道就绪事件
public void channelRead(ChannelHandlerContext ctx, Object msg),通道读取数据事件
public void channelReadComplete(ChannelHandlerContext ctx) ,数据读取完毕事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause),通道发生异常事件
Pipeine 和 ChannePipeline
ChannelPipeline 是一个 Handler 的集合,它负责处理和拦截 inbound 或者 outbound 的事件和操作,相当于一个贯穿 Netty 的链。

 

ChannelPipeline addFirst(ChannelHandler... handlers),把一个业务处理类(handler)添加到链中的第一个位置
ChannelPipeline addLast(ChannelHandler... handlers),把一个业务处理类(handler)添加到链中的最后一个位置
 

ChannelHandlerContext

这 是事 件 处理 器 上 下 文对 象 , Pipeline 链 中 的 实际 处 理 节 点。 每 个 处理 节 点

ChannelHandlerContext  中 包 含 一 个 具 体 的 事 件 处 理 器 ChannelHandler , 同 时

ChannelHandlerContext 中也绑定了对应的 pipeline 和 Channel 的信息,方便对 ChannelHandler

进行调用。常用方法如下所示:

ChannelFuture close(),关闭通道
ChannelOutboundInvoker flush(),刷新
ChannelFuture writeAndFlush(Object msg) , 将 数 据 写 到 ChannelPipeline 中 当 前
ChannelHandler 的下一个 ChannelHandler 开始处理(出站)

ChanneOption
Netty 在创建 Channel 实例后,一般都需要设置 ChannelOption 参数。ChannelOption 是

Socket 的标准参数,而非 Netty 独创的。常用的参数配置有:

ChannelOption.SO_BACKLOG
对应 TCP/IP 协议 listen 函数中的 backlog 参数,用来初始化服务器可连接队列大小。服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接。多个客户端来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理,backlog 参数指定了队列的大小。

ChannelOption.SO_KEEPALIVE ,一直保持连接活动状态。
ChanneFuture
表示 Channel 中异步 I/O 操作的结果,在 Netty 中所有的 I/O 操作都是异步的,I/O 的调用会直接返回,调用者并不能立刻获得结果,但是可以通过 ChannelFuture 来获取 I/O 操作的处理状态。

常用方法如下所示:

Channel channel(),返回当前正在进行 IO 操作的通道
ChannelFuture sync(),等待异步操作执行完毕

EventLoopGroup 和其实现类 NioEventLoopGroup
EventLoopGroup 是一组 EventLoop 的抽象,Netty 为了更好的利用多核 CPU 资源,一般会有多个 EventLoop 同时工作,每个 EventLoop 维护着一个 Selector 实例。

EventLoopGroup 提供 next 接口,可以从组里面按照一定规则获取其中一个 EventLoop 来处理任务。在 Netty 服务器端编程中,我们一般都需要提供两个 EventLoopGroup,例如: BossEventLoopGroup 和 WorkerEventLoopGroup。

通常一个服务端口即一个ServerSocketChannel 对应一个Selector 和一个EventLoop 线程。BossEventLoop 负责接收客户端的连接并将 SocketChannel 交给 WorkerEventLoopGroup 来进行 IO 处理,如下图所示:

 

BossEventLoopGroup 通常是一个单线程的 EventLoop , EventLoop 维护着一个注册了ServerSocketChannel 的 Selector 实例,BossEventLoop 不断轮询 Selector 将连接事件分离出来,通常是 OP_ACCEPT 事件, 然后将接收到的 SocketChannel 交给 WorkerEventLoopGroup , WorkerEventLoopGroup 会由 next 选择其中一个 EventLoopGroup 来将这个 SocketChannel 注册到其维护的 Selector 并对其后续的 IO 事件进行处理。

常用方法如下所示:

public NioEventLoopGroup(),构造方法
public Future<?> shutdownGracefully(),断开连接,关闭线程
ServerBootstrap 和 Bootstrap
ServerBootstrap 是 Netty 中的服务器端启动助手,通过它可以完成服务器端的各种配置; Bootstrap 是 Netty 中的客户端启动助手,通过它可以完成客户端的各种配置。常用方法如下所示:

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup), 该方法用于服务器端,用来设置两个 EventLoop
public B group(EventLoopGroup group) ,该方法用于客户端,用来设置一个 EventLoop
public B channel(Class<? extends C> channelClass),该方法用来设置一个服务器端的通道实现
public <T> B option(ChannelOption<T> option, T value),用来给 ServerChannel 添加配置public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value),用来给接收到的通道添加配置
public ServerBootstrap childHandler(ChannelHandler childHandler),该方法用来设置业务处理类(自定义的 handler)
public ChannelFuture bind(int inetPort) ,该方法用于服务器端,用来设置占用的端口号
public ChannelFuture connect(String inetHost, int inetPort) ,该方法用于客户端,用来连接服务器端

Unpooed 类
这是 Netty 提供的一个专门用来操作缓冲区的工具类,常用方法如下所示:

public static ByteBuf copiedBuffer(CharSequence string, Charset charset),通过给定的数据和字符编码返回一个 ByteBuf 对象(类似于 NIO 中的 ByteBuffer 对象)
入门案例

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion><groupId>cn.itcast.netty</groupId>
<artifactId>NettyDemo</artifactId>
<version>1.0-SNAPSHOT</version><dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>4.1.8.Final</version>
</dependency>
</dependencies><build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>


上述代码在 pom 文件中引入了 netty 的坐标,采用 4.1.8 版本。

//自定义服务器端业务处理类

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override //读取数据事件
public void channelRead(ChannelHandlerContext ctx, Object msg) { System.out.println("Server: " + ctx);
ByteBuf buf = (ByteBuf) msg;                                                System.out.println(" 客户端发来的消息 : " + buf.toString(CharsetUtil.UTF_8));
}
@Override //数据读取完毕事件
public void channelReadComplete(ChannelHandlerContext ctx) { ctx.writeAndFlush(Unpooled.copiedBuffer("就是没钱", CharsetUtil.UTF_8));
}
@Override //异常发生事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace();
ctx.close();
}
}


上述代码定义了一个服务器端业务处理类,继承 ChannelInboundHandlerAdapter,并分别重写了三个方法。

public class NettyServer {
public static void main(String[] args) throws Exception{
//1.创建一个线程组:用来处理网络事件(接受客户端连接) EventLoopGroup bossGroup = new NioEventLoopGroup();
//2.创建一个线程组:用来处理网络事件(处理通道 IO 操作)
EventLoopGroup workerGroup = new NioEventLoopGroup();


 
//3.创建服务器端启动助手来配置参数ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) //4.设置两个线程组 EventLoopGroup
.channel(NioServerSocketChannel.class) //5.使用 NioServerSocketChannel 作为服务器
端通道实现
.option(ChannelOption.SO_BACKLOG, 128) //6.设置线程队列中等待连接的个数
.childOption(ChannelOption.SO_KEEPALIVE, true) //7.保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() { //8.创建一个通道初始化对象public void initChannel(SocketChannel sc) { //9.往 Pipeline 链中添加自定义的业务
处理 handler
sc.pipeline().addLast(new NettyServerHandler()); //服务器端业务处理类
System.out.println(".......Server is ready.......");
}
});
//10.启动服务器端并绑定端口,等待接受客户端连接(非阻塞) ChannelFuture cf = b.bind(9999).sync(); System.out.println("......Server is Starting......");
 
//11.关闭通道,关闭线程池cf.channel().closeFuture().sync(); bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
}
}
上述代码编写了一个服务器端程序,配置了线程组,配置了自定义业务处理类,并绑定端口

号进行了启动

//自定义客户端业务处理类
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
@Override    //通道就绪事件
public void channelActive(ChannelHandlerContext ctx) { System.out.println("Client: " + ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("老板,还钱吧", CharsetUtil.UTF_8));
}
@Override //通道读取数据事件
public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf in = (ByteBuf) msg;
System.out.println("服务器端发来的消息 : " + in.toString(CharsetUtil.UTF_8));
}
@Override    //数据读取完毕事件
public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush();
}
@Override //异常发生事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.close();
}
}
上述代码自定义了一个客户端业务处理类,继承 ChannelInboundHandlerAdapter ,并分别重写了四个方法。

public class NettyClient {
public static void main(String[] args) throws Exception {
//1.创建一个 EventLoopGroup 线程组
EventLoopGroup group = new NioEventLoopGroup();
//2.创建客户端启动助手Bootstrap b = new Bootstrap();
b.group(group) //3.设置 EventLoopGroup 线程组
.channel(NioSocketChannel.class) //4.使用 NioSocketChannel 作为客户端通道实现
.handler(new ChannelInitializer<SocketChannel>() { //5.创建一个通道初始化对象
@Override
protected void initChannel(SocketChannel sc) { //6.往 Pipeline 链中添加自定义的业务
处 理 handler sc.pipeline().addLast(new NettyClientHandler()); //客户端业务处理类System.out.println("......Client is ready.......");
}
});


//7.启动客户端,等待连接上服务器端(非阻塞) ChannelFuture cf = b.connect("127.0.0.1", 9999).sync();
//8.等待连接关闭(非阻塞) cf.channel().closeFuture().sync();
}
}
上述代码编写了一个客户端程序,配置了线程组,配置了自定义的业务处理类,并启动连接

​​​​​​​

了服务器端。最终运行效果如下图所示:

 

​​​​​​​网络聊天案例

实现一个多人聊天案例,具体代码如下所示:

//自定义一个服务器端业务处理类

public class ChatServerHandler extends SimpleChannelInboundHandler<String> { public static List<Channel> channels = new ArrayList<>();
@Override //通道就绪
public void channelActive(ChannelHandlerContext ctx) { Channel incoming = ctx.channel(); channels.add(incoming);
System.out.println("[Server]:"+incoming.remoteAddress().toString().substring(1)+"在线");
}
@Override //通道未就绪
public void channelInactive(ChannelHandlerContext ctx) { Channel incoming = ctx.channel(); channels.remove(incoming);
System.out.println("[Server]:"+incoming.remoteAddress().toString().substring(1)+"掉线");
}
@Override //读取数据
protected void channelRead0(ChannelHandlerContext ctx, String s) { Channel incoming = ctx.channel();
for (Channel channel : channels) {
if (channel != incoming){ //排除当前通道
channel.writeAndFlush("[" + incoming.remoteAddress().toString().substring(1) + "]说: " + s
+ "\n");
}
}
}
@Override //发生异常
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { Channel incoming = ctx.channel();
System.out.println("[Server]:"+incoming.remoteAddress().toString().substring(1)+"异常"); ctx.close();
}
}


上述代码通过继承 SimpleChannelInboundHandler 类自定义了一个服务器端业务处理类,

并在该类中重写了四个方法,当通道就绪时,输出在线;当通道未就绪时,输出下线;当通   道发来数据时,读取数据;当通道出现异常时,关闭通道。

//聊天程序服务器端

public class ChatServer {private int port; //服务器端端口号public ChatServer(int port) {
this.port = port;
}public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline(); //得到 Pipeline 链
//往 Pipeline 链中添加一个解码器
pipeline.addLast("decoder", new StringDecoder());
//往 Pipeline 链中添加一个编码器
pipeline.addLast("encoder", new StringEncoder());
//往 Pipeline 链中添加一个自定义的业务处理对象
pipeline.addLast("handler", new ChatServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true); System.out.println("Netty Chat Server 启 动 ......"); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); System.out.println("Netty Chat Server 关闭......");
}
}public static void main(String[] args) throws Exception { new ChatServer(9999).run();
}
}


上述代码通过 Netty 编写了一个服务器端程序,里面要特别注意的是:我们往 Pipeline 链中添加了处理字符串的编码器和解码器,它们加入到 Pipeline 链中后会自动工作,使得我们在服务器端读写字符串数据时更加方便(不用人工处理 ByteBuf)。

//自定义一个客户端业务处理类

public class ChatClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { System.out.println(s.trim());
}
}


上述代码通过继承 SimpleChannelInboundHandler 自定义了一个客户端业务处理类,重写了一个方法用来读取服务器端发过来的数据。

//聊天程序客户端public class ChatClient {
private final String host; //服务器端 IP 地址
private final int port; //服务器端端口号public ChatClient(String host, int port) { this.host = host;
this.port = port;
}public void run(){
EventLoopGroup group = new NioEventLoopGroup(); try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch){
ChannelPipeline pipeline = ch.pipeline(); //得到 Pipeline 链
//往 Pipeline 链中添加一个解码器
pipeline.addLast("decoder", new StringDecoder());
//往 Pipeline 链中添加一个编码器
pipeline.addLast("encoder", new StringEncoder());
//往 Pipeline 链中添加一个自定义的业务处理对象
pipeline.addLast("handler", new ChatClientHandler());
}
});
Channel channel = bootstrap.connect(host, port).sync().channel(); System.out.println("--------"+channel.localAddress().toString().substring(1)+"--------"); Scanner scanner=new Scanner(System.in);
while (scanner.hasNextLine()) { String msg=scanner.nextLine();
channel.writeAndFlush(msg + "\r\n");
}
} catch (Exception e) { e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}public static void main(String[] args) throws Exception { new ChatClient("127.0.0.1", 9999).run();
}


上述代码通过 Netty 编写了一个客户端程序,里面要特别注意的是:我们往 Pipeline 链中添加了处理字符串的编码器和解码器,他们加入到 Pipeline 链中后会自动工作,使得我们在客户端读写字符串数据时更加方便(不用人工处理 ByteBuf)。

我们可以同时运行多个聊天客户端,运行效果如下图所示:

 

编码和解码

概述

我们在编写网络应用程序的时候需要注意 codec (编解码器),因为数据在网络中传输的都是二进制字节码数据,而我们拿到的目标数据往往不是字节码数据。因此在发送数据时就   需要编码,接收数据时就需要解码。

codec 的组成部分有两个:decoder(解码器)和 encoder(编码器)。encoder 负责把业务数据转换成字节码数据,decoder 负责把字节码数据转换成业务数据。

其实 Java 的序列化技术就可以作为 codec 去使用,但是它的硬伤太多:

无法跨语言,这应该是 Java 序列化最致命的问题了。
序列化后的体积太大,是二进制编码的 5 倍多。
序列化性能太低。
       由于 Java 序列化技术硬伤太多,因此 Netty 自身提供了一些 codec,如下所示: Netty 提供的解码器:

StringDecoder, 对字符串数据进行解码
ObjectDecoder,对 Java 对象进行解码
. ... ... ...
    Netty 提供的编码器:

StringEncoder,对字符串数据进行编码
ObjectEncoder,对 Java 对象进行编码
    3. ... ... ...

Netty 本身自带的 ObjectDecoder 和 ObjectEncoder 可以用来实现 POJO 对象或各种业务对象的编码和解码,但其内部使用的仍是 Java 序列化技术,所以我们不建议使用。因此对于 POJO 对象或各种业务对象要实现编码和解码,我们需要更高效更强的技术。

Google 的 Protobuf

Protobuf 是 Google 发布的开源项目,全称 Google Protocol Buffers,特点如下:

支持跨平台、多语言(支持目前绝大多数语言,例如 C++、C#、Java、python 等)
高性能,高可靠性
使用 protobuf 编译器能自动生成代码,Protobuf 是将类的定义使用.proto 文件进行描述,然后通过 protoc.exe 编译器根据.proto 自动生成.java 文件
 

目前在使用 Netty 开发时,经常会结合 Protobuf 作为 codec (编解码器)去使用,具体用法如下所示。

第 1 步:

<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>4.1.8.Final</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.6.1</version>
</dependency>
</dependencies>


上述代码在 pom 文件中分别引入 netty 和 protobuf 的坐标。

第 2 步:假设我们要处理的数据是图书信息,那就需要为此编写 proto 文件

 
      
第 3 步:通过 protoc.exe 根据描述文件生成 Java 类,具体操作如下所示:

 

 

第四步:把生成的 BookMessage.java 拷贝到自己的项目中打开,如下图所示:

这个类我们不要编辑它,直接拿着用即可,该类内部有一个内部类,这个内部类才是真正的

POJO,一定要注意。

 

第 5 步:在 Netty 中去使用


————————————————
版权声明:本文为CSDN博主「再遇当年」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_15204179/article/details/86744371

 


http://chatgpt.dhexx.cn/article/SeAbTLMS.shtml

相关文章

Netty框架基本介绍

NIO 1.概述&#xff1a;NIO全称java non-blocking IO &#xff0c;是指JDK1.4开始&#xff0c;java提供了一系列改进的输入/输出的新特性&#xff0c;被统称为NIO(即New IO )。新增了许多用于处理输入输出的类&#xff0c;这些类都被放在java.nio包及子包下&#xff0c;并且对j…

超详细Netty入门,看这篇就够了!

思维导图 前言 本文主要讲述Netty框架的一些特性以及重要组件&#xff0c;希望看完之后能对Netty框架有一个比较直观的感受&#xff0c;希望能帮助读者快速入门Netty&#xff0c;减少一些弯路。 一、Netty概述 官方的介绍&#xff1a; Netty is an asynchronous event-drive…

SPI通信协议详解(一)

SPI是一个同步的数据总线&#xff0c;也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和接收端的完美同步。 时钟是一个振荡信号&#xff0c;它告诉接收端在确切的时机对数据线上的信号进行采样。 产生时钟的一侧称为主机&#xff0c;另一侧称为从机。总是只有一个…

SPI协议的介绍

学习内容&#xff1a; 学习SPI协议记录 学习清单&#xff1a; 提示&#xff1a;这里可以添加要学的内容 例如&#xff1a; SPI协议的介绍三根线还是四根线两个概念四种模式SPI时序图SPI优缺点SPI和IIC的对比 学习详细内容&#xff1a; 1.SPI协议的介绍 SPI是串口外设接口…

SPI 通信协议

文章目录 【 1. 概述 】【 2. 原理 】1. 全双工特征下的传输特点2. 二线式、三线式的SPI3. SPI 模式CPOL(Clock Polarity)&#xff0c;时钟极性CPHA (Clock Phase)&#xff0c;时钟相位通信模式_时序 4. 通信过程5. 底层数据传输演示 【 3. SPI底层驱动 】 【 1. 概述 】 SPI …

SPI通信协议基础

文章目录 引言正文串行与并行通信SPI通信简介SPI如何运作&#xff1f;时钟从机选择多个从机MOSI和MISOSPI数据传输步骤 SPI的优缺点优点缺点 好文推荐参考 引言 当您将微控制器连接到传感器&#xff0c;显示器或其他模块时&#xff0c;您是否考虑过这两种设备如何相互通信&…

SPI、I2C、UART(即串口)三种串行总线详解

以下内容均来源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 参考博客 几个串口协议学习整理 UART IIC SPI_mainn的博客-CSDN博客 SPI、I2C、UART三种串行总线的原理、区别及应用_嵌入式Linux,的博客-CSDN博客 RS-232 和 UART 之间有什么区别&#xff1f; - 知乎…

uart、spi、i2c通信协议详解

文章目录 前言一、uart&#xff08;串口&#xff09;介绍使用rs232、rs485拓展 二、I2C介绍1.宏观流程2.时序上3.典型操作 三、spi&#xff08;串行外设接口&#xff09;介绍使用1.宏观上2.微观上 总结1.i2c和spi对比 前言 之前对于各种通信协议学习了就忘&#xff0c;学了就忘…

普通GPIO模拟SPI通信协议(软件SPI)

在工作中偶尔会遇到SPI不够用的情况&#xff0c;而我们又要去使用SPI通信协议&#xff0c;此时就需要我们自己去模拟SPI通信协议。我们知道SPI通信协议有四种模式&#xff0c;它们分别如下所示&#xff1a; 下面是我基于ATSAM4SD16B芯片在Atmel Studio上用普通GPIO模拟的SPI…

SPI 协议

一. 概念 1. 通常SPI通信要求4根线&#xff0c;分别是MOSI(mast output salve input), MISO, CLK, CS。 2. 当发送和接受数据的工作都准备好了&#xff0c;只要有时钟CLK,就发送数据&#xff0c;没有时钟就不发送&#xff0c;而且一个时钟周期发送一位(bit)数据&#xff0c;所…

SPI通信协议(SPI总线)学习

转载自&#xff1a;https://www.cnblogs.com/deng-tao/p/6004280.html 1、什么是SPI&#xff1f; SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一 种同步串行接口技术&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总…

SPI通信

1 SPI的简介及基本特点 1 SPI的简单介绍 最近工作中使用了SPI通信方式来做TM4C129和STM32之间的通信&#xff0c;为了更好地解决问题就学习了SPI原理的相关内容&#xff0c;完成了项目之后&#xff0c;也对这种通信方式有了较为深入的了解&#xff0c;现在来对SPI的使用方法进…

详解SPI通信协议

一、SPI简介 SPI&#xff0c;即Serial Peripheral Interface的英文缩写。从字面意思看就是串行外部设备接口&#xff0c;是一种全双工、高速、同步的通信总线。 SPI最早是摩托罗拉公司开发的全双工同步串行总线&#xff0c;用于微控制器&#xff08;MCU&#xff09;连接外部设…

stm32中常见的通信协议之SPI

目录 1.SPI总线2.SPI的寻址方式3.SPI的工作原理总结4.SPI的通讯过程5.SPI的极性和相位6.IIC和SPI的异同7.stm32中SPI配置中常用的寄存器8.stm32中相关库函数 1.SPI总线 SPI是串行外设接口的缩写&#xff0c;SPI是一种高速的、全双工、同步的串行通信协议&#xff1b;SPI采用主…

【通信协议】一文搞懂SPI

SPI总线简介 SPI(Serial Peripheral Interface)是 Motorola 公司推出的一种同步串行接口技术&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线。 接口定义 SPI接口共有4根信号线&#xff0c;分别是&#xff1a;片选信号、时钟信号、串行输出信号、串行…

SPI 通信协议 最详细解读!!!

SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外围接口&#xff09;是一种高速、全双工、同步的通信总线&#xff0c;主要应用在EEPROM、FLASH、实时时钟、AD转换器上&#xff0c;以及数字信号处理器和数字信号解码器之间。 信号线 SPI有四根信号线&#xff1a;…

SPI 通信协议详解

SPI通信协议详解 写在最前: 本文讲述了SPI通信协议的基本内容包括如下 SPI的基础知识SPI的读写时序 本文重点参考 英文维基百科 中文维基百科 百度百科 注意: 倘若读者有足够的耐心和英文水平&#xff0c;强烈建议自行去英文维基百科去阅读相关知识。 相关链接&#xff1a; SPI…

通信协议篇——SPI通信

通信协议篇——SPI通信 1.简介 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种高速、同步、全双工串行通信总线&#xff0c;采用主从机通信模式&#xff0c;主要应用在EEPROM&#xff0c;FLASH&#xff0c;实时时钟&#xff0c;AD转换器等。 2.原理 通信方…

SPI接口通信协议详解:SPI时序、2线、3线、4线SPI及4种常用工作模式

简介 SPI通信原理比I2C要简单&#xff0c;它主要是主从方式通信。这种模式通常只有一个主机和一个或者多个从机&#xff0c;标准的SPI是4根线&#xff0c;分别是SSEL(片选&#xff0c;也写作 SCS)、SCLK(时钟&#xff0c;也写作SCK)、MOSI(主机输出从机输入Master Output/Slav…

详解UART、I2C、SPI常用通信协议(全是细节)

前言 UART、I2C和SPI是我们在嵌入式开发中比较常见的通信协议了&#xff0c;没有最好的通信协议&#xff0c;每个通信协议都有自己的优缺点。如果想要通信速度快&#xff0c;SPI 将是理想的选择&#xff1b;如果用户想要连接多个设备而不是过于复杂&#xff0c;I2C 将是理想的选…