基于Netty的网络编程项目实战

2021/6/18 17:29:27

本文主要是介绍基于Netty的网络编程项目实战,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Netty介绍与相关基础知识

  • Netty提供异步的事件驱动的网络应用程序框架和工具,用以快速开发高性能,高可靠性的网络服务器和客户端程序。
    • Netty提供了简单易用的API
    • 基于事件驱动的编程方式来编写网络通信程序
    • 更高吞吐量
    • 学习难度低

BIO、NIO、AIO 介绍与区别

  • 阻塞与非阻塞
    在这里插入图片描述

  • 同步和异步
    在这里插入图片描述

  • BIO 同步阻塞IO,block io IO操作时会阻塞线程,并发处理能力低。

  • NIO 同步非阻塞IO ,NIO是对BIO的改进,基于Reactor模型。

  • AIO(NIO2.0) 异步非阻塞IO 完成了客户端请求处理,在通知服务器去启动线程进行处理。

Netty Reactor模型 -单线程模型、多线程模型、主从多线程模型

  • 单线程模型
    在这里插入图片描述

  • Reactor 多线程模型
    在这里插入图片描述
    但是如果并发仍然很大,Reactor 仍然无法处理大量的客户端请求

  • Reactor 主从多线程模型

这种线程模型是 Netty 推荐使用的线程模型,
这种模型适用于高并发场景,一组线程池接收请求,一组线程池处理 IO。
在这里插入图片描述

Netty - 基于 web socket 简单聊天 DEMO 实现

  • 导入依赖
   <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.15.Final</version>
        </dependency>
    </dependencies>
  • 编写 Netty Server 后端代码
public class WebsocketServer {
    public static void main(String[] args) {
        //创建两个线程池
        NioEventLoopGroup mainGroup = new NioEventLoopGroup();
        NioEventLoopGroup subGroup = new NioEventLoopGroup();

        try {
            //创建Netty服务器启动对象
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //初始化容器启动对象
            serverBootstrap
                    //指定使用上面创建的两个线程池
                    .group(mainGroup, subGroup)
                    //指定Netty通道类型
                    .channel(NioServerSocketChannel.class)
                    //指定通道初始化器用来加载 当Channel收到事件后
                    //进行业务处理
                    .childHandler(new WebSocketChanelInitailizer());
            //绑定服务器端口,已同步的方式启动服务器
            ChannelFuture future = serverBootstrap.bind(9090).sync();
            //等待服务器关闭
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //关闭服务器
            mainGroup.shutdownGracefully();
            subGroup.shutdownGracefully();
        }
    }
}
/**
 * 通道初始化器,用来加载通道处理器(ChanelHandler)
 *
 * @Author chenppeng
 * @Date 2021-06-03 10:58
 * @Version 1.0
 */
@SuppressWarnings("all")
public class WebSocketChanelInitailizer extends ChannelInitializer<SocketChannel> {

    /**
     * 初始化通道,这个方法主要是加载对应的ChannelHandler
     *
     * @param socketChannel
     * @throws Exception
     */
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //获取管道,将一个一个的ChannelHandler加载到管道中
        ChannelPipeline pipeline = socketChannel.pipeline();
        //添加一个http的编解码器
        pipeline.addLast(new HttpServerCodec());
        //添加一个用户支持大数据流的支持
        pipeline.addLast(new ChunkedWriteHandler());
        //添加一个聚合器,这个聚合器主要是将HttpMessage聚合成FullHttpRequest/Response
        pipeline.addLast(new HttpObjectAggregator(1024 * 64));
        //需要指定接受请求的路由
        //必须使用以ws后缀结尾的url才能访问
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        //添加自定义hanlder
        pipeline.addLast(new ChatHandler());
    }
}
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     * 用户保存所有的客户端连接
     */
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 时间格式解析器
     */
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd hh:MM:ss");

    /**
     * 当Channel中有新的事件消息会自动调用
     *
     * @param channelHandlerContext
     * @param textWebSocketFrame
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        //当接受到数据后 会自动调用
        //获取客户端发送过来的文本消息
        String text = textWebSocketFrame.text();
        System.out.println("接受到的消息数据为:" + text);
        for (Channel client : clients) {
            //将消息发送给所有的客户端
            client.writeAndFlush(new TextWebSocketFrame(simpleDateFormat.format(new Date()) + ":" + text));
        }
    }

    /**
     * 当有新的客户端li连接服务器之后,会自动调用这个方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //将新的通道加入到clients
        clients.add(ctx.channel());
    }
}

  • 编写前端代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>在线聊天室</title>
</head>
<body>
<label for="message"><input type="text" id="message"></label>
<input type="button" value="发送消息"  onclick="SendMessage()">

接受到的消息
<p id="server_message" style="background-color: #AAAAAA"></p>

<script>
    let websocket = null;
    //判断当前浏览器是否支持web socket
    if (window.WebSocket) {
        //连接到服务器并发送消息
        websocket = new WebSocket("ws://127.0.0.1:9090/ws");
        websocket.onopen = function () {
            console.log("建立连接");
        };

        websocket.onclose = function () {
            console.log("断开连接")
        };

        websocket.onmessage = function (e) {
            console.log("接受到服务器的消息:" + e.data);
            document.getElementById("server_message").innerHTML += e.data + "<br>";
        }
    } else {
        alert("当前浏览器不支持 web socket")
    }

    function SendMessage() {
        let message = document.getElementById("message");
        websocket.send(message.value);
    }
</script>
</body>
</html>

MUI、HTML5+、HBuilder 介绍

  • MUI 官网 http://dev.dcloud.net.cn/mui/
  • API地址:http://dev.dcloud.net.cn/mui/ui/

MUI 是一个轻量级的前端框架。MUI 以 iOS 平台 UI 为基础,补充部分 Android 平台特有的 UI 控件。MUI 不依赖任何第三方 JS 库,压缩后的 JS 和 CSS 文件仅有 100+K 和 60+K,可以根据自己的需要,自定义去下载对应的模块。并且 MUI 编写的前端,可以打包成 APK 和 IPA 安装文件,在手机端运行。也就是,编写一套代码,就可以在 Android、
IOS 下运行。

  • HTML5+ API地址http://www.html5plus.org/doc/zh_cn/accelerometer.html#

H5+提供了对 HTML5 的增强,提供了 40WAPI 给程序员使用。使用 H5+ API 可以轻松开发二维码扫描、摄像头、地图位置、消息推送等功能

  • HBuilder 下载地址 http://www.dcloud.io/

用户登录功能

在这里插入图片描述
在这里插入图片描述

  • 后台业务代码
 @Override
    public User login(String username, String password) {
        if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
            TbUserExample tbUserExample = new TbUserExample();
            TbUserExample.Criteria criteria = tbUserExample.createCriteria();
            criteria.andUsernameEqualTo(username);
            List<TbUser> userList = tbUserMapper.selectByExample(tbUserExample);
            if (userList != null && userList.size() == 1) {
                String pwd = DigestUtils.md5DigestAsHex(password.getBytes());
                if (pwd.equals(userList.get(0).getPassword())) {
                    User user = new User();
                    BeanUtils.copyProperties(userList.get(0), user);
                    return user;
                }
            }
        }
        return null;
    }

注册功能

在这里插入图片描述
在这里插入图片描述

  • 后台业务代码
@Override
    public void register(TbUser tbUser) {
        //判断用户在数据库是否存在
        TbUserExample example = new TbUserExample();
        TbUserExample.Criteria criteria = example.createCriteria();
        criteria.andUsernameEqualTo(tbUser.getUsername());
        List<TbUser> userList = tbUserMapper.selectByExample(example);
        if (userList != null && userList.size() > 0) {
            throw new RuntimeException("注册失败");
        }
        //将用户信息保存到数据库中
        tbUser.setId(idWorker.nextId());
        tbUser.setPassword(DigestUtils.md5DigestAsHex(tbUser.getPassword().getBytes()));
        tbUser.setPicSmall("");
        tbUser.setPicNormal("l");
        tbUser.setNickname(tbUser.getUsername());
        tbUser.setCreatetime(new Date());
        tbUserMapper.insert(tbUser);
    }

FastDFS 文件服务器介绍与搭建

FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
在这里插入图片描述

  • springboot整合fastdfs 上传用户头像
    • application.properties配置文件
#整合FASTDFS
fdfs.soTimeout=1501
fdfs.connectTimeout=601 
#缩略图生成参数
fdfs.thumbImage.width=150
fdfs.thumbImage.height=150
#TrackerList参数,支持多个
fdfs.trackerList[0]=192.168.25.135:22122

#HTTP URL
fdfs.httpurl=http://192.168.25.135/

上传头像业务层

 @Override
    public User upload(MultipartFile file, String userid) {
        try {
            //返回的fastdfs中的url路径,这个路径不带http://192.168.1.133/..
            String url = fastDFSClient.uploadFile(file);
            //在fastDFS上传的时候,会自动生成一个缩略图  文件名_150*150,后缀
            String[] fileNameList = url.split("\\.");
            String fileName = fileNameList[0];
            String ext = fileNameList[1];
            String picSmallUrl = fileName + "_150x150." + ext;
            String prefix = environment.getProperty("fdfs.httpurl");
            TbUser tbUser = tbUserMapper.selectByPrimaryKey(userid);
            //设置头像大图片
            tbUser.setPicNormal(prefix + url);
            //设置头像小图片
            tbUser.setPicSmall(prefix + picSmallUrl);
            //将新的头像url更新到数据库里面
            tbUserMapper.updateByPrimaryKey(tbUser);
            User user = new User();
            BeanUtils.copyProperties(tbUser, user);
            return user;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


这篇关于基于Netty的网络编程项目实战的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程