netty-简易聊天

Netty :Netty介绍 & 实现简易多人聊天室 Netty :Netty介绍 & 实现简易多人聊天室 博主在去年二月份就介绍了Java原生网络编程API,并用它们实现了多种I/O模型的简易多人聊天室: Java网络编程-Socket编程初涉一(简易客户端-服务器) Java网络编程-Socket编程初涉二(基于BIO模型的简易多人聊天室) Java网络编程-Socket编程初涉三(伪异步I/O模型的简易多人聊天室) Java网络编程-Socket编程初涉四(NIO模型的简易多人聊天室) Java网络编程-Socket编程初涉五 阅读详情

界面:

package com.zy.nettychat;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class ClientFrame extends Frame {
    public static final ClientFrame INSTANCE = new ClientFrame();
    private TextArea ta = new TextArea();
    private TextField tf = new TextField();
    private ChatClient chatClient;
    public ClientFrame() {
        this.setTitle("聊天室");
        this.setSize(300,400);
        this.setLocation(400, 20);
        this.add(ta, BorderLayout.CENTER);
        this.add(tf, BorderLayout.SOUTH);

       // 输入监听
        tf.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                chatClient.send(tf.getText());

                tf.setText("");
            }
        });

        // 关闭监听

        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                chatClient.closeConnect();
                System.exit(0);
            }
        });
    }

    // 启动时,客户端连接服务器
    public void connectToServer() {
        chatClient = new ChatClient();
        chatClient.connect();
    }

    public static void main(String[] args) {
        ClientFrame clientFrame = ClientFrame.INSTANCE;
        clientFrame.setVisible(true);
        clientFrame.connectToServer();

    }

    public void updateText(String str) {
        ta.setText(ta.getText() + str + System.lineSeparator());
    }
}

客户端:

package com.zy.nettychat;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.ReferenceCountUtil;

public class ChatClient {
    private Channel channel;

    public void connect() {
        // 负责服务
        EventLoopGroup workerGroup = new NioEventLoopGroup(4);

        // 服务类
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workerGroup);

        bootstrap.channel(NioSocketChannel.class);
        // netty帮我们内部处理了accept过程
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                channel = socketChannel;
                socketChannel.pipeline().addLast(new MyHandler());
            }
        });

        try {
            ChannelFuture channelFuture = bootstrap.connect("localhost", 8888).sync();
            // closeFuture表示如果有人调用了channel的close的方法,那么才会拿到close的future
            // 如果没有关,就会阻塞到这里
            channelFuture.channel().closeFuture().sync();
        }  catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

    public void send(String text) {
        channel.writeAndFlush(Unpooled.copiedBuffer(text.getBytes()));
    }

    public void closeConnect() {
        send("__bye__");
        channel.close();
    }
}

class MyHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = null;
        try {
            buf = (ByteBuf) msg;
            byte[] bytes = new byte[buf.readableBytes()];
            buf.getBytes(buf.readerIndex(), bytes);
            String str = new String(bytes);
            System.out.println(str);
            System.out.println(buf.refCnt());
            // 将数据更新到界面上
            ClientFrame.INSTANCE.updateText(str);
        } finally {
            if (buf != null) {
                ReferenceCountUtil.release(buf);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

服务器:

package com.zy.nettychat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.Objects;

public class ChatServer {
    // 负责装载所有的客户端chnnel,方便向客户端写数据
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    public static void main(String[] args) {
        // 负责接客
        EventLoopGroup bossGroup = new NioEventLoopGroup(2);

        // 负责服务
        EventLoopGroup workerGroup = new NioEventLoopGroup(4);

        // 服务类
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);

        bootstrap.channel(NioServerSocketChannel.class);
        // netty帮我们内部处理了accept过程
        bootstrap.childHandler(new MyServerChildInitializer());
        try {
            ChannelFuture channelFuture = bootstrap.bind(8888).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

class MyServerChildInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline().addLast(new MyChildHandler());
        System.out.println("a client connected !");
    }
}

class MyChildHandler extends ChannelInboundHandlerAdapter {
    // 表示客户端通道可用,因此在这里面添加客户端chnnel
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ChatServer.clients.add(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.getBytes(buf.readerIndex(), bytes);
        String str = new String(bytes);
        System.out.println("客户端数据:" + str);
        if (Objects.equals(str, "__bye__")) {
            System.out.println("client ready to quit");
            ChatServer.clients.remove(ctx.channel()); // 会自动释放buf,不需要显式关闭
            ctx.close();
        } else {
            ChatServer.clients.writeAndFlush(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ChatServer.clients.remove(ctx.channel());
        cause.printStackTrace();
        ctx.close();
    }
}

Encoder和Decoder

例如将坦克的位置传输给服务器,可以有两种方式:

第一种:

"30,20".getBytes() ->服务器

第二种:

30->[0100110011011...]   32位字节数组

20->[...]                            32位字节数组

将8byte send to Server->

两种方式哪种更好???

第二种最好

字符串长度不固定,编码不固定,甚至语言不固定。并且转字符串效率比较低。(为什么低呢???)

编码器和解码器由Netty自动识别调用,不用担心在需要Encoder时会误调用Decoder,也不用担心在需要Decoder时误用encoder

多种不同的编解码器可以混在一起使用共同实现程序的业务逻辑。

定义消息

package com.zy.nettycoder;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@ToString
public class TankMsg {
    private int x;
    private int y;

    public TankMsg(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

客户端:

package com.zy.nettycoder;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.ReferenceCountUtil;

public class TankClient {
    private Channel channel;

    public void connect() {
        // 负责服务
        EventLoopGroup workerGroup = new NioEventLoopGroup(4);

        // 服务类
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workerGroup);

        bootstrap.channel(NioSocketChannel.class);
        // netty帮我们内部处理了accept过程
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                channel = socketChannel;
                socketChannel.pipeline()
                        .addLast(new TankMsgEncoder()) // 天添加编码器,貌似必 须在handler之前啊!!!
                        .addLast(new TankMsgClientHandler());
            }
        });

        try {
            ChannelFuture channelFuture = bootstrap.connect("localhost", 8888).sync();
            // closeFuture表示如果有人调用了channel的close的方法,那么才会拿到close的future
            // 如果没有关,就会阻塞到这里
            channelFuture.channel().closeFuture().sync();
        }  catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

    public void send(String text) {
        channel.writeAndFlush(Unpooled.copiedBuffer(text.getBytes()));
    }

    public void closeConnect() {
        send("__bye__");
        channel.close();
    }
}

class TankMsgClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(new TankMsg(5, 8));
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = null;
        try {
            buf = (ByteBuf) msg;
            byte[] bytes = new byte[buf.readableBytes()];
            buf.getBytes(buf.readerIndex(), bytes);
            String str = new String(bytes);
            System.out.println(str);
            System.out.println(buf.refCnt());
        } finally {
            if (buf != null) {
                ReferenceCountUtil.release(buf);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    public static void main(String[] args) {
        new TankClient().connect();
    }
}

定义编码器:

package com.zy.nettycoder;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

public class TankMsgEncoder extends MessageToByteEncoder<TankMsg> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, TankMsg tankMsg, ByteBuf byteBuf) throws Exception {
        byteBuf.writeInt(tankMsg.getX());
        byteBuf.writeInt(tankMsg.getY());

    }
}

定义服务器:

package com.zy.nettycoder;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;

public class TankMsgServer {
    // 负责装载所有的客户端chnnel,方便向客户端写数据
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public static void serverStart() {
        // 负责接客
        EventLoopGroup bossGroup = new NioEventLoopGroup(2);

        // 负责服务
        EventLoopGroup workerGroup = new NioEventLoopGroup(4);

        // 服务类
        ServerBootstrap bootstrap = new ServerBootstrap();
        // 异步全双工
        bootstrap.group(bossGroup, workerGroup);

        bootstrap.channel(NioServerSocketChannel.class);
        // netty帮我们内部处理了accept过程
        bootstrap.childHandler(new TankMsgServerChildInitializer());
        try {
            ChannelFuture channelFuture = bootstrap.bind(8888).sync();
            TankMsgServerFrame.INSTANCE.updateServerMsg("server started!");
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

class TankMsgServerChildInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline()
                .addLast(new TankMsgDecoder())
                .addLast(new TankMsgChildHandler());
        System.out.println("a client connected !");
    }
}

class TankMsgChildHandler extends ChannelInboundHandlerAdapter {
    // 表示客户端通道可用,因此在这里面添加客户端chnnel
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        TankMsgServer.clients.add(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("开始读取数据!!!");
        TankMsg tankMsg = (TankMsg) msg;
        TankMsgServerFrame.INSTANCE.updateClientMsg(tankMsg.toString());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        TankMsgServer.clients.remove(ctx.channel());
        cause.printStackTrace();
        ctx.close();
    }
}

定义解码器:

package com.zy.nettycoder;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

public class TankMsgDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        System.out.println("TankMsgDecoder1111");
        if (byteBuf.readableBytes() < 8) {
            return;
        }

        int x = byteBuf.readInt();
        int y = byteBuf.readInt();

        list.add(new TankMsg(x, y));
    }
}

定义服务器界面:

package com.zy.nettycoder;

import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TankMsgServerFrame extends Frame {
    public static final TankMsgServerFrame INSTANCE = new TankMsgServerFrame();

    private TextArea taServer = new TextArea();
    private TextArea taClient = new TextArea();

    public TankMsgServerFrame() throws HeadlessException {
        this.setSize(800, 600);
        this.setLocation(300, 30);
        Panel panel = new Panel(new GridLayout(1, 2));
        panel.add(taServer);
        panel.add(taClient);
        this.add(panel);
        taServer.setFont(new Font("Consolas", Font.PLAIN, 25));
        taClient.setFont(new Font("Consolas", Font.PLAIN, 25));
        updateServerMsg("server:");
        updateClientMsg("client:");

        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    public void updateServerMsg(String text) {
        taServer.setText(taServer.getText() + text + System.lineSeparator());
    }

    public void updateClientMsg(String text) {
        taClient.setText(taClient.getText() + text + System.lineSeparator());
    }

    public static void main(String[] args) {
        TankMsgServerFrame.INSTANCE.setVisible(true);
        TankMsgServer.serverStart();
    }
}

效果:

单元测试:

package com.zy.nettycoder;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Assert;

public class TankMsgTest {

    @org.junit.Test
    public void decode() {
        EmbeddedChannel embeddedChannel = new EmbeddedChannel();
        embeddedChannel.pipeline().addLast(new TankMsgDecoder());
        ByteBuf buf = Unpooled.buffer();
        buf.writeInt(5);
        buf.writeInt(8);

        embeddedChannel.writeInbound(buf);

        TankMsg tankMsg = embeddedChannel.readInbound();
        Assert.assertEquals(tankMsg.getX(), 5);
        Assert.assertEquals(tankMsg.getY(), 8);

    }

    @org.junit.Test
    public void encode() {
        EmbeddedChannel embeddedChannel = new EmbeddedChannel();
        embeddedChannel.pipeline().addLast(new TankMsgEncoder());
        TankMsg tankMsg = new TankMsg(5, 8);
        embeddedChannel.writeOutbound(tankMsg);

        ByteBuf buf = embeddedChannel.readOutbound();
        int x = buf.readInt();
        int y = buf.readInt();
        Assert.assertEquals(x, 5);
        Assert.assertEquals(y, 8);
    }
}

使用EmbeddedChannel模拟出来一个通道。

Encode是Out Bound

Decode是in Bound

 

 

 

 

Netty实现简易聊天室的功能 使用Netty来实现一个聊天室是很容易的,当有客户端连接服务端的时候,在服务端的channelActive方法里面即可感应到。这里的解决方案是发送每条数据的时候,将数据的长度一并发送,比如可以选择每条数据的前4位是数据的长度,应用层处理时可以根据长度来判断每条数据的开始和结束。同理,channelInactive是该客户端断开服务端时会回调的方法,在里面给其他客户端发一条“下线了”的信息即可。如果数据长度不够length,就等待下一次数据过来,取数据的时候也只取length长度的数据。 阅读详情

相关推荐

netty实现在线聊天

概念篇 1.Netty 是什么? Netty 是一款基于 NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于 BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。难能可贵的是,在保证快速和易用性的同时,并没有丧失可维护性和性能等优势。 2.Netty 的特点是什么? **高并发:**Netty 是一款基于 NIO(Nonblocking IO,非阻塞IO)开发的网络通信框架,对比于 BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提

LynRaen的博客 1162

Ansible自动化平台执行环境配置终极指南:10个关键步骤详解

Ansible自动化平台的执行环境配置是workshops培训课程中的核心技术环节,它确保了自动化任务的一致性和可靠性。本文将详细介绍如何在gh_mirrors/workshops/workshops项目中配置和管理执行环境,帮助您快速掌握这一重要技能。执行环境配置是Ansible自动化平台的核心功能,它通过容器化技术为自动化任务提供标准化的运行环境,确保在不同系统上获得一致的执行结果。 ##

gitblog_00047的博客 568

netty点对点聊天保存聊天记录

接着这一篇点对点通讯的来,请先弄懂netty实现点对点通讯的原理 效果 聊天界面 聊天记录 实现方案 1首先拼接用户id和好友id在Redis数据库中注册key值 Jedis jedis = new Jedis("xxx.xx.xx.xxx", 6379); //权限认证 jedis.auth("xxxx"); ...

weixin_39168678的博客 2313

DeepSeek-V3服务化部署:构建企业级AI推理API的完整方案

想要将强大的DeepSeek-V3大语言模型转化为可用的企业级AI推理服务吗?🤔 本文为您提供完整的DeepSeek-V3服务化部署指南,帮助您快速构建稳定、高效的AI推理API,让您的企业应用轻松接入6710亿参数的先进AI能力!🚀 DeepSeek-V3是深度求索于2024年12月发布的开源大语言模型,采用创新的混合专家(MoE)架构,在数学推理、代码生成和知识理解等任务中表现出色。通过

gitblog_01058的博客 511

nettychat实时聊天室源码websocket

netty实时聊天源代码,主要是实现技术,websocket加http。

NettyChat:基于Netty + TCP + Protobuf实现的Android IM库,包含Protobuf序列化,TCP拆包与粘包,长连接握手认证,心跳机制,断线重连机制,消息重发机制,读写超时机制,离线消息,螺纹池等功能

使用方式 1. 依赖im_lib库,implementation project(':im_lib') 2. 自定义IMSEventListener,实现OnEventListener,重写对应的方法配置参数 3. 自定义IMSConnectStatusListener,实现IMSConnectStatusCallback,重现对应的方法监听ims连接状态 4. 调用IMSClientInterface.init(Vector<String> serverUrlList, OnEventListener listener, IMSConnectStatusCallback callback)方法,把服务器地址列表、IMSEventListener、IMSConnectStatusListener三个参数传入即可。 5. 发送消息:调用IMSClientInterface.sendMsg(M

Netty-Chat: 构建高性能实时聊天系统的利器

Netty-Chat: 构建高性能实时聊天系统的利器 是一个基于 Netty 框架构建的实时聊天系统示例项目,它展示了如何利用 Java NIO 和 Netty 的强大功能来创建高效、可靠的网络通信应用。本文将深入探讨该项目的技术细节,应用潜力,以及其独特之处,以帮助更多开发者了解并开始使用 Netty-Chat。 项目简介 Netty-Chat 是一个包含服务器端和客户端的多用户聊天平台,它演示...

gitblog_00018的博客 1097

claude使用教程

提供了三种模型:claude,codex, gemini,三种模型都共用同一个apikey, 有开发需求使用claude效果较好,知识问答等场景gemini效果会更好些,本文只提供了claude的安装方式,剩下两种按需按照以下参考链接安装下即可,安装有问题参考文档:https://www.aicodemirror.com/dashboard/official-installation/macos-linux (不需要挂梯子,自己手机号注册就好)

lichao19871216的博客 3493

探索Netty Chat: 实时通信的新篇章

探索Netty Chat: 实时通信的新篇章 去发现同类优质开源项目:https://gitcode.com/ 是一个基于Java和Netty框架构建的实时聊天应用示例项目。它展示了如何利用Netty的高性能网络库来实现高效、稳定且可扩展的在线通信系统。本文将深入探讨该项目的技术细节、应用场景及特点,帮助开发者了解并开始使用Netty Chat。 项目简介 Netty Chat旨在为开发者提供一个...

gitblog_00035的博客 430

ST-LINK调试STM32H743必看:CubeMX工程中缺失的这行代码导致程序跑飞

本文深入剖析了使用ST-LINK调试STM32H743时,因CubeMX工程中缺失电源电压档位配置代码而导致程序跑飞或出现“Can not access memory”错误的问题。文章解释了H7系列电源与时钟耦合的核心原理,提供了具体的代码修复方案和系统化的调试排查思路,帮助开发者从根本上解决这一常见调试困境。

weixin_29191669的博客 281

S32K3实战:手把手教你用eMIOS模块实现电机PWM控制(附代码)

本文详细解析了NXP S32K3系列MCU的eMIOS模块在电机PWM控制中的应用,从硬件设计到软件实现,再到调试与优化,提供了完整的实战指南。通过eMIOS模块的硬件级PWM生成能力,工程师可以实现高精度的电机控制,适用于汽车电子和工业控制领域。

weixin_42570484的博客 147

金融情感分析终极指南:使用Distilbert模型快速分析财报新闻的完整教程

在当今数据驱动的金融世界中,**金融情感分析**已经成为投资决策和风险管理的必备工具。本指南将为您详细介绍如何使用**Distilbert-base-uncased-finetuned-cola**这一强大的预训练模型,快速准确地分析财报新闻和市场评论,帮助您把握市场情绪变化。这个专为金融领域优化的模型能够以98.23%的准确率识别文本中的积极、中性和负面情感,为投资者提供宝贵的市场洞察。 ##

gitblog_00283的博客 502

MAX30102心率血样模块在STM32F103芯片的程序说明

我希望你已经安装好了Keil MDK5这个软件,也安装了M3内核,可以编译一些STM32F103的一些项目下载程序后步骤: 1-按照下图找到IIC.uvprojx并打开(途中唯一绿色那个图标) 2-编译一次 3-确保0错误,0警告,下图所示 4-点击目标选项,然后找到STM32F103C8,再点debug–CMSIS****(我实际用的JTAG,用不了,选择这个CMSIS****即可)下图所示 5-下图所示,看看你的串口找到了没,找到了就点左下角的OK 6-按图上传到开发板 7-MAX30102接线方法

weixin_51357422的博客 5801

Netty搭建简易聊天室

NIO框架Netty搭建简易聊天室 Netty Reactor模型 单线程模型 用户发起 IO 请求到 Reactor 线程 Ractor 线程将用户的 IO 请求放入到通道,然后再进行后续处理 处理完成后,Reactor 线程重新获得控制权,继续其他客户端的处理 缺点: 这种模型一个时间点只有一个任务在执行,这个任务执行完了,再去执行下一个任务。 但单线程的 Reactor 模型每一个用户事...

jl935418600的博客 1393

Duilib的简单使用(五、DuiDesigner/DuiEditor的下载编译)

一、前言 在Duilib的简单使用(一、duilib demo)中我们介绍了利用duilib简单的构造一个项目 在Duilib的简单使用(二、xml实现界面与业务分离)中我们介绍了XML在duilib中的使用 在Duilib的简单使用(三、界面逻辑交互)中我们已经知道如何简单的进行界面的交互 在Duilib的简单使用(四、换肤)中,我们提了一下Duilib强大的一键换肤功能。 通过之前的说明,我们知道duilib是通过xml来分离界面和业务逻辑的,但是xml如果不能预览,那每次敲一个再运行一下看看效果,这不

LyRics1996的博客 2888

深入浅出一文搞懂Raft协议

前言 在分布式的世界里,要说最核心最复杂的功能,一致性的实现无出其右,之前的paxos算法堪称经典,被认为是同类算法中效果最好的,基本上成为分布式一致性的代名词,但是paxos算法也是出了名的难理解,而且相当不好实现。本人也花了很多时间、看了很多材料也没有真正理解。所以基于paxos的思想进行的一致性算法的简化和实现就成为了现实的需求,在此背景下,本文的主角Raft就出现了。 Raft算法的头号目标就是容易理解(UnderStandable),这从论文中就可以看出来。当然,R...

microGP的专栏 6485

Netty版-简易聊天室

通过Netty实现简易聊天室

namelessmyth的专栏 1447

Hermes Dashboard Web 端部署完整说明

通过反向代理(nginx)使用公网域名访问时,会遇到 Host 头校验、CORS 跨域、WebSocket 连接拒绝三个核心问题。本文档记录了完整的源码修改方案和部署步骤。确保 nginx 主配置加载了 WebSocket map(宝塔默认为。路径的公开访问(无需登录),其他路径仍受 Cookie 认证保护。Hermes Dashboard 默认绑定。访问站点时会先弹出浏览器密码框,输入用户。在 nginx 反向代理配置中的。环境变量动态读取允许的域名。nginx 配置中已添加。

大白菜代码的博客 805

基于netty的多人多聊天室

上篇文章已经详细介绍了如何基于netty搭建一个多人单聊天室(https://blog.csdn.net/baidu_37147070/article/details/99131686),那么怎么建一个多人多聊天室呢? 其实,实现的方法并不难,我是借助使用redis来实现的,我们从代码中可以知道,对于每个聊天的channel,是通过ChannelGroup来管理的,也就是每个进来的通道,...

向日葵班学霸的博客 1890

docker 安装oracle

本文介绍了使用Docker部署Oracle数据库的实践指南。主要内容包括:常用Oracle镜像的阿里云和华为云拉取地址,11g/12c/19c等不同版本的启动命令示例,以及连接数据库的基本信息。实战部分详细演示了Oracle 11g的安装过程,包括镜像拉取、容器启动、密码修改和数据库连接步骤,并通过Sql Developer和命令行两种方式创建用户。最后提到数据持久化的重要性,建议将数据库文件挂载到宿主机目录以防止容器删除导致数据丢失。文章提供了完整的操作命令和截图说明,适合需要快速部署Oracle测试环境

weixin_39766667的博客 373

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

java netty聊天室_基于netty搭建一个聊天室

前言上篇博文(netty实现消息中心(一)思路整理)大概说了下netty websocket消息中心的设计思路,这篇文章主要说说简化版的netty聊天室代码实现,支持群聊和点对点聊天。此demo主要说明netty实现消息推送的基本使用方法,如果需要扩充其它功能,可以基于此脚手架扩展。完整项目代码地址:netty聊天室github源码介绍1.登录页面login.png2.聊天页面index.png核...

weixin_32520565的博客 902

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

利用Netty,从零到一实现自己的简易实时聊天系统

从零到一实现自己的建议实时聊天, 聊天主页面收到新消息后提示并刷新最新消息,消息已读/未读状态实时变更,消息实时收与发。

Fealiy的博客 1980

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Netty--聊天业务

推荐 了解 消息推送中的已读消息和未读消息设计问题 站内信问题难点 Netty websocket 实现简单聊天功能的相关

Kaka_csdn14的博客 2201

Netty 群聊私聊聊天室

Netty实现简易聊天室 文章目录Netty实现简易聊天室1.协议定制1.1协议格式:1.2编解码器:2.黏包半包问题3.封装消息3.1Message3.2AbstractResponseMessage3.3其他消息4.处理连接断开5.实现会话6.具体业务的实现6.1单对单聊天6.2客户端退出7.假死与心跳8.核心代码 在Netty 的学习结束之后就很想去实现一个简单的聊天室,在参考黑马视频之外,添加自己的理解和处理实现了一个建议的聊天室,本聊天室将实现简单的几个技术需求: 定制协议 协议格式定制 协

Jeffrey_oWang的博客 1056

基于Netty的WebSocket聊天室Demo

这个项目基于Netty 4.1.x、Spring Boot、Spring WebFlux,构建了一个基于WebSocket协议的多人聊天室Demo。这个项目能够帮助我们快速学习、了解Netty和WebSocket。

Spencercjh 928

Netty 实现聊天功能简易版demo

Netty是一个 Java NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。更多关于 Netty 的知识,可以参阅《Netty 4.x 用户指南》(https://github.com/waylau/netty-4-user-guide) 下面,就基于 Ne...

shuangyueliao的专栏 846
上一篇: 前缀树
下一篇: MongoDB初识
给自己加加油
博客等级 码龄8年 302粉丝 110原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值