两万字详解!Netty经典32连问! 2

简介: 两万字详解!Netty经典32连问! 2

15. Netty 中的各种 Codec 是什么,它们的作用是什么?

Netty 中,Codec 是一种将二进制数据与 Java 对象之间进行编码和解码的组件。它们可以将数据从字节流解码为 Java 对象,也可以将 Java 对象编码为字节流进行传输。

以下是 Netty 中常用的 Codec

  • ByteToMessageCodec:将字节流解码为 Java 对象,同时也可以将 Java 对象编码为字节流。可以用于处理自定义协议的消息解析和封装。
  • MessageToByteEncoder:将 Java 对象编码为字节流。通常用于发送消息时将消息转换为二进制数据。
  • ByteToMessageDecoder:将字节流解码为 Java 对象。通常用于接收到数据后进行解码。
  • StringEncoder 和 StringDecoder:分别将字符串编码为字节流和将字节流解码为字符串。
  • LengthFieldPrepender 和 LengthFieldBasedFrameDecoder:用于处理 TCP 粘包和拆包问题。
  • ObjectDecoder和ObjectEncoder:将Java对象序列化为字节数据,并将字节数据反序列化为Java对象。

这些 Codec 组件可以通过组合使用来构建复杂的数据协议处理逻辑,以提高代码的可重用性和可维护性。

16. 什么是 Netty 的 BootStrap,它的作用是什么?

Netty的Bootstrap是一个用于启动和配置Netty客户端和服务器的工具类。它提供了一组简单易用的方法,使得创建和配置Netty应用程序变得更加容易。

Bootstrap类提供了一些方法,可以设置服务器或客户端的选项和属性,以及为ChannelPipeline配置handler,以处理传入或传出的数据。一旦完成配置,使用Bootstrap启动客户端或服务器。

Netty应用程序中,Bootstrap有两个主要作用:

  • 作为Netty服务器启动的入口点:通过Bootstrap启动一个Netty服务器,可以在指定的端口上监听传入的连接,并且可以设置服务器的选项和属性。
  • 作为Netty客户端启动的入口点:通过Bootstrap启动一个Netty客户端,可以连接到远程服务器,并且可以设置客户端的选项和属性。

17.Netty的IO模型是什么?与传统的BIO和NIO有什么不同?

NettyIO模型是基于事件驱动的NIO(Non-blocking IO)模型。在传统的BIO(Blocking IO)模型中,每个连接都需要一个独立的线程来处理读写事件,当连接数过多时,线程数量就会爆炸式增长,导致系统性能急剧下降。而在NIO模型中,一个线程可以同时处理多个连接的读写事件,大大降低了线程的数量和切换开销,提高了系统的并发性能和吞吐量。

与传统的NIO模型相比,NettyNIO模型有以下不同点:

  • Netty使用了Reactor模式,将IO事件分发给对应的Handler处理,使得应用程序可以更方便地处理网络事件。
  • Netty使用了多线程模型,将Handler的处理逻辑和IO线程分离,避免了IO线程被阻塞的情况。
  • Netty支持多种Channel类型,可以根据应用场景选择不同的Channel类型,如NIO、EPoll、OIO等。

18. 如何在Netty中实现TCP粘包/拆包的处理?

TCP传输过程中,由于TCP并不了解上层应用协议的消息边界,会将多个小消息组合成一个大消息,或者将一个大消息拆分成多个小消息发送。这种现象被称为TCP粘包/拆包问题 。在Netty中,可以通过以下几种方式来解决TCP粘包/拆包问题:

  • 消息定长 :将消息固定长度发送,例如每个消息都是固定的100字节。在接收端,根据固定长度对消息进行拆分。
// 编码器,将消息的长度固定为100字节
pipeline.addLast("frameEncoder", new LengthFieldPrepender(2));
pipeline.addLast("messageEncoder", new StringEncoder(CharsetUtil.UTF_8));
// 解码器,根据固定长度对消息进行拆分
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(100, 0, 2, 0, 2));
pipeline.addLast("messageDecoder", new StringDecoder(CharsetUtil.UTF_8));
  • 消息分隔符 :将消息以特定的分隔符分隔开,例如以"\r\n"作为分隔符。在接收端,根据分隔符对消息进行拆分。
// 编码器,以"\r\n"作为消息分隔符
pipeline.addLast("frameEncoder", new DelimiterBasedFrameEncoder("\r\n"));
pipeline.addLast("messageEncoder", new StringEncoder(CharsetUtil.UTF_8));
// 解码器,根据"\r\n"对消息进行拆分
pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(1024, Delimiters.lineDelimiter()));
pipeline.addLast("messageDecoder", new StringDecoder(CharsetUtil.UTF_8));
  • 消息头部加长度字段 :在消息的头部加上表示消息长度的字段,在发送端发送消息时先发送消息长度,再发送消息内容。在接收端,先读取消息头部的长度字段,再根据长度读取消息内容。
// 编码器,将消息的长度加入消息头部
pipeline.addLast("frameEncoder", new LengthFieldPrepender(2));
pipeline.addLast("messageEncoder", new StringEncoder(CharsetUtil.UTF_8));
// 解码器,先读取消息头部的长度字段,再根据长度读取消息内容
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 0, 2, 0, 2));
pipeline.addLast("messageDecoder", new StringDecoder(CharsetUtil.UTF_8));

19. Netty如何处理大文件的传输?

Netty中,可以通过使用ChunkedWriteHandler处理大文件的传输。ChunkedWriteHandler是一个编码器,可以将大文件切分成多个Chunk,并将它们以ChunkedData的形式写入管道,这样就可以避免一次性将整个文件读入内存,降低内存占用。

具体使用方法如下:

  • 在服务端和客户端的ChannelPipeline中添加ChunkedWriteHandler
pipeline.addLast(new ChunkedWriteHandler());
  • 在服务端和客户端的业务逻辑处理器中,接收并处理ChunkedData
public class MyServerHandler extends SimpleChannelInboundHandler<Object> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            // 处理HTTP请求
            // ...
        } else if (msg instanceof HttpContent) {
            HttpContent content = (HttpContent) msg;
            // 处理HTTP内容
            if (content instanceof LastHttpContent) {
                // 处理完整个HTTP请求
                // ...
            } else if (content instanceof HttpChunkedInput) {
                HttpChunkedInput chunkedInput = (HttpChunkedInput) content;
                // 处理ChunkedData
                while (true) {
                    HttpContent chunk = chunkedInput.readChunk(ctx.alloc());
                    if (chunk == null) {
                        break;
                    }
                    // 处理单个Chunk
                    // ...
                }
            }
        }
    }
}
  • 在客户端向服务端发送数据时,将需要传输的文件包装成ChunkedFile并写入管道。
public void sendFile(Channel channel, File file) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    DefaultFileRegion fileRegion = new DefaultFileRegion(raf.getChannel(), 0, raf.length());
    HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
    HttpUtil.setContentLength(request, raf.length());
    channel.write(request);
    channel.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, file.length(), 8192)));
}

在传输大文件时,还需要注意以下几点

  • 使用ChunkedFile时需要指定Chunk的大小,根据实际情况选择合适的大小,一般建议不要超过8KB
  • 为了避免大文件传输过程中对网络造成影响,可以在服务端和客户端的ChannelPipeline中添加WriteBufferWaterMark,限制写入缓冲区的大小。
pipeline.addLast(new WriteBufferWaterMark(8 * 1024, 32 * 1024));

20. 如何使用Netty实现心跳机制?

Netty中,可以通过实现一个定时任务来实现心跳机制。具体来说,就是在客户端和服务端之间定时互相发送心跳包,以检测连接是否仍然有效。

以下是使用Netty实现心跳机制的基本步骤

  • 定义心跳消息的类型。
public class HeartbeatMessage implements Serializable {
    // ...
}
  • 在客户端和服务端的ChannelPipeline中添加IdleStateHandler,用于触发定时任务。
pipeline.addLast(new IdleStateHandler(0, 0, 60, TimeUnit.SECONDS));
  • 在客户端和服务端的业务逻辑处理器中,重写userEventTriggered方法,在触发定时任务时发送心跳包。
public class MyServerHandler extends SimpleChannelInboundHandler<Object> {
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                // 读空闲,发送心跳包
                ctx.writeAndFlush(new HeartbeatMessage());
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
  • 在客户端和服务端的业务逻辑处理器中,重写channelRead方法,接收并处理心跳包。
public class MyClientHandler extends SimpleChannelInboundHandler<Object> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HeartbeatMessage) {
            // 收到心跳包,不做处理
            return;
        }
        // 处理其他消息
        // ...
    }
}

需要注意的是,由于心跳包不需要传输大量数据,因此建议使用Unpooled.EMPTY_BUFFER作为心跳包的内容。另外,心跳间隔的时间应根据实际情况设置,一般建议设置为连接的超时时间的一半。

21. Netty中如何实现SSL/TLS加密传输?

Netty 中实现 SSL/TLS 加密传输,需要通过 SSLHandler来进行处理。通常情况下,SSLHandler 需要在 ChannelPipeline 中作为最后一个handler添加。

以下是实现 SSL/TLS 加密传输的示例代码:

// 创建 SSLContext 对象,用于构建 SSLEngine
SSLContext sslContext = SSLContext.getInstance("TLS");
// 初始化 SSLContext
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("server.jks"), "password".toCharArray());
keyManagerFactory.init(keyStore, "password".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
// 获取 SSLEngine
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
// 添加 SslHandler 到 ChannelPipeline 中
pipeline.addLast("ssl", new SslHandler(sslEngine));

22. NioEventLoopGroup 默认的构造函数会起多少线程?

默认情况下,NioEventLoopGroup 的构造函数会根据可用的处理器核心数 (availableProcessors()) 创建相应数量的线程。

具体来说,NioEventLoopGroup 的默认构造函数内部调用了另一个构造函数,其参数 nThreads 的默认值为 0,表示使用默认线程数。而默认线程数的计算方式就是调用 Runtime.getRuntime().availableProcessors() 方法获取当前机器可用的处理器核心数。

因此,如果你在一台四核的机器上创建了一个默认的 NioEventLoopGroup 实例,那么它就会使用四个线程。如果你想要修改线程数,可以调用 NioEventLoopGroup 的其他构造函数,并传入自定义的线程数。

23. 如何使用Netty实现WebSocket协议?

Netty 中实现 WebSocket 协议,需要使用 WebSocketServerProtocolHandler 进行处理。WebSocketServerProtocolHandler 是一个 ChannelHandler,可以将 HTTP 升级为 WebSocket 并处理 WebSocket 帧。

以下是实现 WebSocket 协议的示例代码:

// 添加 HTTP 请求解码器
pipeline.addLast("httpDecoder", new HttpRequestDecoder());
// 添加 HTTP 响应编码器
pipeline.addLast("httpEncoder", new HttpResponseEncoder());
// 添加 HTTP 聚合器
pipeline.addLast("httpAggregator", new HttpObjectAggregator(65536));
// 添加 WebSocket 服务器协议处理器
pipeline.addLast("webSocketHandler", new WebSocketServerProtocolHandler("/ws"));
// 添加自定义的 WebSocket 处理器
pipeline.addLast("handler", new MyWebSocketHandler());

在以上示例代码中,WebSocketServerProtocolHandler 的参数 "/ws" 表示 WebSocket 请求的 URL 路径,MyWebSocketHandler 是自定义的 WebSocket 处理器。

24. Netty 高性能表现在哪些方面?

  • 异步非阻塞 I/O 模型:Netty 使用基于NIO的异步非阻塞 I/O 模型,可以大大提高网络通信效率,减少线程的阻塞等待时间,从而提高应用程序的响应速度和吞吐量。
  • 零拷贝技术:Netty 支持零拷贝技术,可以避免数据在内核和用户空间之间的多次复制,减少了数据拷贝的次数,从而提高了数据传输的效率和性能。
  • 线程模型优化:Netty 的线程模型非常灵活,可以根据不同的业务场景选择不同的线程模型。例如,对于低延迟和高吞吐量的场景,可以选择 Reactor 线程模型,对于 I/O 操作比较简单的场景,可以选择单线程模型。
  • 内存池技术:Netty 提供了一套基于内存池技术的 ByteBuf 缓冲区,可以重用已经分配的内存空间,减少内存的分配和回收次数,提高内存使用效率。
  • 处理器链式调用:Netty ChannelHandler 可以按照一定的顺序组成一个处理器链,当事件发生时,会按照处理器链的顺序依次调用处理器,从而实现对事件的处理。这种处理方式比传统的多线程处理方式更加高效,减少了线程上下文切换和锁竞争等问题。

25. Netty 和 Tomcat 的区别?

Netty 和 Tomcat 都是 Java Web 应用服务器,但是它们之间存在一些区别:

  • 底层网络通信模型不同:Tomcat 是基于阻塞的 BIO(Blocking I/O)模型实现的,而 Netty 是基于 NIO(Non-Blocking I/O)模型实现的。
  • 线程模型不同:Tomcat 使用传统的多线程模型,每个请求都会分配一个线程,而 Netty 使用 EventLoop 线程模型,每个 EventLoop 负责处理多个连接,通过线程池管理 EventLoop
  • 协议支持不同:Tomcat 内置支持 HTTP 和 HTTPS 协议,而 Netty 不仅支持 HTTP 和 HTTPS 协议,还支持 TCP、UDP 和 WebSocket 等多种协议。
  • 代码复杂度不同:由于Tomcat支持的功能比较全面,所以其代码相对较为复杂,而 Netty 的代码相对比较简洁、精简。
  • 应用场景不同:Tomcat 适合于处理比较传统的 Web 应用程序,如传统的 MVC 模式Web应用程序;而 Netty 更适合于高性能、低延迟的网络应用程序,如游戏服务器、即时通讯服务器等。

26. 服务端Netty的工作架构图

             ┌───────┐        ┌───────┐
             │ Channel │◀───────│ Socket│
             │Pipeline │        │       │
             └───────┘        └───────┘
                   ▲                 │
                   │                 │
         ┌─────────┴─────────┐       │
         │                   │       │
         ▼                   ▼       ▼
┌──────────────┐   ┌──────────────┐  ┌──────────────┐
│EventLoopGroup│   │EventLoopGroup│  │EventLoopGroup│
│       boss   │   │     work     │  │     work     │
└──────────────┘   └──────────────┘  └──────────────┘
         ▲                   ▲       ▲
         │                   │       │
┌────────┴─────────┐ ┌────────┴─────────┐
│     NioServerSocketChannel   │   NioSocketChannel      │ ...

整个服务端 Netty 的工作架构图包括了以下几个部分:

  • ChannelPipeline:管道处理器,用于处理入站或出站事件,对数据进行编解码、处理业务逻辑等。
  • Channel:通道,对应底层的 Socket 连接,用于收发网络数据。
  • EventLoopGroup:事件循环组,包含了多个事件循环(EventLoop),每个事件循环负责处理多个通道上的事件。
  • EventLoop:事件循环,负责监听注册到该循环的多个通道上的事件,然后根据事件类型将事件派发给对应的处理器。
  • NioServerSocketChannel:NIO 服务端通道,用于接受客户端的连接。
  • NioSocketChannel:NIO 客户端通道,用于和服务端进行数据通信。

在服务端启动时,会创建一个或多个 EventLoopGroup。其中一个 EventLoopGroup 作为boss线程池,用于接受客户端的连接请求,并将连接请求分发给work线程池中的某个 EventLoopwork 线程池中的EventLoop负责处理已经连接的客户端的数据通信。每个 EventLoop 负责处理一个或多个 NioSocketChannel,并维护该通道的事件队列,当事件发生时,将事件添加到事件队列中,并将事件派发到管道处理器中进行处理。

27. 简单聊聊:Netty的线程模型的三种使用方式?

Netty的线程模型有三种使用方式,分别是单线程模型、多线程模型和主从多线程模型。

  • 单线程模型 :所有的I/O操作都由同一个线程来执行。虽然这种方式并不适合高并发的场景,但是它具有简单、快速的优点,适用于处理I/O操作非常快速的场景,例如传输小文件等。
  • 多线程模 型:所有的I/O操作都由一组线程来执行,其中一个线程负责监听客户端的连接请求,其他线程负责处理I/O操作。这种方式可以支持高并发,但是线程上下文切换的开销较大,适用于处理I/O操作较为耗时的场景。
  • 主从多线程模型 :所有的I/O操作都由一组NIO线程来执行,其中一个主线程负责监听客户端的连接请求,其他从线程负责处理I/O操作。这种方式将接受连接和处理I/O操作分开,避免了线程上下文切换的开销,同时又能支持高并发,适用于处理I/O操作耗时较长的场景。

28. Netty 是如何保持长连接的

  • 心跳机制 :使用心跳机制可以定期向服务器发送一个简短的数据包,以保持连接处于活动状态。如果在一段时间内没有收到心跳包,就可以认为连接已经断开,从而及时重新建立连接。Netty提供了IdleStateHandler处理器,可以方便地实现心跳机制。
  • 断线重连机制 :在网络不稳定的情况下,连接可能会不可避免地断开。为了避免因为网络异常导致应用程序不能正常工作,可以实现断线重连机制,定期检查连接状态,并在连接断开时尝试重新连接。Netty提供了ChannelFutureListener接口和ChannelFuture对象,可以方便地实现断线重连机制。
  • 基于HTTP/1.1协议的长连接HTTP/1.1协议支持长连接,可以在一个TCP连接上多次发送请求和响应。在Netty中,可以使用HttpClientCodec和HttpObjectAggregator处理器,实现基于HTTP/1.1协议的长连接。
  • WebSocket协议WebSocket协议也支持长连接,可以在一个TCP连接上双向通信,实现实时数据交换。在Netty中,可以使用WebSocketServerProtocolHandlerWebSocketClientProtocolHandler处理器,实现WebSocket协议的长连接。

29. Netty 发送消息有几种方式?

Netty 中,发送消息主要有以下三种方式:

  • Channel.write(Object msg) :通过 Channel 写入消息,消息会被缓存到 Channel 的发送缓冲区中,等待下一次调用 flush() 将消息发送出去。
  • ChannelHandlerContext.write(Object msg) :通过 ChannelHandlerContext 写入消息,与 Channel.write(Object msg) 相比,ChannelHandlerContext.write(Object msg) 会将消息写入到 ChannelHandlerContext 的发送缓冲区中,等待下一次调用 flush() 将消息发送出去。
  • ChannelHandlerContext.writeAndFlush(Object msg) :通过 ChannelHandlerContext 写入并发送消息,等同于连续调用 ChannelHandlerContext.write(Object msg) ChannelHandlerContext.flush()

在使用上述三种方式发送消息时,需要注意到写操作可能会失败或被延迟,因此需要在发送消息时进行一定的错误处理或者设置超时时间。另外,也可以使用 Netty 提供的 ChannelFuture 对象来监听操作结果或者进行异步操作。

30. Netty 支持哪些心跳类型设置?

Netty 中,可以通过以下几种方式实现心跳机制:

  • IdleStateHandlerNetty 内置的空闲状态检测处理器,支持多种空闲状态检测(如读空闲、写空闲、读写空闲)。
  • 自定义心跳检测机制 :可以通过自定义实现 ChannelInboundHandler 接口的处理器来实现心跳检测,例如可以通过计时器或者线程来定期发送心跳包,或者通过对远程端口的连接状态进行检测等方式实现。
  • 使用心跳应答 :在应用层面定义心跳请求和应答消息,通过 ChannelInboundHandler 处理器监听接收到的心跳请求消息,并返回心跳应答消息,来实现心跳检测。如果一段时间内未收到对方的心跳应答消息,则认为连接已经失效。

需要注意的是,为了避免因心跳机制导致的网络负载过大或者频繁的连接断开和重连,应该根据具体业务场景选择适合的心跳类型和频率。

31. Netty的内存管理机制是什么?

Netty 的内存管理机制主要是通过 ByteBuf 类实现的。ByteBufNetty 自己实现的一个可扩展的字节缓冲区类,它在 JDKByteBuffer 的基础上做了很多优化和改进。

Netty ByteBuf 的内存管理主要分为两种方式:

  • 堆内存:ByteBuf 以普通的字节数组为基础,在 JVM 堆上分配内存。这种方式适用于小型数据的传输,如传输的是文本、XML 等数据。
  • 直接内存:ByteBuf 使用操作系统的堆外内存,由操作系统分配和回收内存。这种方式适用于大型数据的传输,如传输的是音视频、大型图片等数据。

对于堆内存,Netty 采用了类似于JVM 的分代内存管理机制,将缓冲区分为三种类型:堆缓冲区、直接缓冲区、复合缓冲区 。Netty 会根据不同的使用场景和内存需求来决定使用哪种类型的缓冲区,从而提高内存利用率。

在使用 ByteBuf 时,Netty 还实现了一些优化和特殊处理,如池化缓冲区、零拷贝等技术,以提高内存的利用率和性能的表现。

32. Netty 中如何实现高可用和负载均衡?

Netty本身并没有提供高可用和负载均衡的功能,但可以结合其他技术来实现这些功能。下面介绍一些常用的方案:

  • 高可用:通过在多台服务器上部署同一个应用程序实现高可用。可以使用负载均衡器来将请求分配给不同的服务器,当某台服务器出现故障时,负载均衡器可以将请求转发给其他可用的服务器。常用的负载均衡器包括Nginx、HAProxy等。
  • 负载均衡:负载均衡是将请求分配给多台服务器的过程,常用的负载均衡算法包括轮询、随机、权重 等。在Netty中可以使用多个EventLoop来处理请求,将请求分配给不同的EventLoop,从而实现负载均衡。另外,可以使用第三方框架,如Zookeeper、Consul等,来实现服务注册、发现和负载均衡。
  • 高可用与负载均衡的结合:可以使用多台服务器来实现高可用和负载均衡。在每台服务器上部署同一个应用程序,并使用负载均衡器来分配请求。当某台服务器出现故障时,负载均衡器可以将请求转发给其他可用的服务器,从而保证高可用和负载均衡。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
4月前
|
JSON 安全 fastjson
使用阿里巴巴 Fastjson 替代 Spring Boot 默认的 Jackson
本文介绍在 Spring Boot 项目中如何替换默认的 Jackson,集成阿里巴巴 Fastjson 作为 JSON 处理框架。内容涵盖 Fastjson 与 Jackson 的核心对比、依赖配置、自定义消息转换器、null 值统一处理及循环引用控制,并提供安全建议与最佳实践,助你高效、安全地使用 Fastjson。
|
SQL 关系型数据库 MySQL
MySQL Workbench的安装与配置
MySQL Workbench的安装与配置
|
数据采集 数据挖掘 数据处理
探索“数据菜谱”无限可能:首届Data-Juicer大模型数据竞赛
数据是LLaMA、Alpaca等大语言模型(LLM) 的“食物” ,你心中的大模型米其林菜单会是什么样呢?
|
存储 人工智能 文字识别
AI与OCR:数字档案馆图像扫描与文字识别技术实现与项目案例
本文介绍了纸质档案数字化的技术流程,包括高精度扫描、图像预处理、自动边界检测与切割、文字与图片分离抽取、档案识别与文本提取,以及识别结果的自动保存。通过去噪、增强对比度、校正倾斜等预处理技术,提高图像质量,确保OCR识别的准确性。平台还支持多字体识别、批量处理和结构化存储,实现了高效、准确的档案数字化。具体应用案例显示,该技术在江西省某地质资料档案馆中显著提升了档案管理的效率和质量。
1812 1
|
物联网 网络性能优化 网络架构
关闭 2.4GHz 会让 5GHz 更快吗?
【5月更文挑战第10天】
2503 4
关闭 2.4GHz 会让 5GHz 更快吗?
|
JavaScript 前端开发
原生js实现走马灯效果
原生js实现走马灯效果
275 0
|
小程序 JavaScript Java
智慧校园|智慧校园管理小程序|基于微信小程序的智慧校园管理系统设计与实现(源码+数据库+文档)
智慧校园|智慧校园管理小程序|基于微信小程序的智慧校园管理系统设计与实现(源码+数据库+文档)
554 0
|
存储 Java API
Netty实战(五)ByteBuf—Netty的数据容器
网络数据的基本单位总是字节。Java NIO 提供了 ByteBuffer 作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐。**ByteBuffer 替代品是 ByteBuf**,一个强大的实现,既解决了 JDK API 的局限性,又为网络应用程序的开发者提供了更好的 API。
615 0
|
监控 网络协议 Linux
centos常见的命令
【5月更文挑战第8天】了解和掌握基本的CentOS命令对于服务器管理至关重要。本文介绍了19个常用命令,包括`ls`、`cd`、`mkdir`、`rm`、`grep`、`find`、`sudo`、`vi/vim`、`cp/mv`、`du/df`、`history`、`top/htop`、`ps`、`netstat/ss`、`yum/dnf`、`ssh`、`iptables`、`journalctl`、`crontab`和`systemctl`。每个命令都提到了常见问题、使用技巧和避免错误的方法,帮助用户更好地管理和维护CentOS系统。
596 0

热门文章

最新文章