netty编程实战01-创建一个tcp服务端程序

简介: netty编程实战01-创建一个tcp服务端程序

相信如果是搞java的大伙在工作一两年后一定听过 netty 的大名,使用netty我们可以简单快速的开发出tcp、udp连接协议的程序。

本文带给大家一个netty程序的server端实战演练,麻雀虽小,五脏俱全,具体讲解都在代码中

pom配置

<?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>com.wayn.nettyproject</groupId>
    <artifactId>netty-project</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>netty-project</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--netty依赖-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId> <!-- Use 'netty-all' for 4.0 or above -->
            <version>4.1.72.Final</version>
        </dependency>
        <!--lombok 依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <!--##### log4j2 start  ####-->
        <!--log4j2核心包-->
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.1</version>
        </dependency>
        <!--用于与slf4j保持桥接(里面自动依赖了slf4j-api)-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.17.1</version>
        </dependency>
        <!-- 异步日志,需要加入disruptor依赖 -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.4</version>
        </dependency>
        <!--##### log4j2 end  ####-->
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.18</version>
        </dependency>
    </dependencies>
    <build>
    </build>
</project>

tcp服务端

/**
 * tcp服务端
 */
@Slf4j
public class NettyServer {
    // 绑定端口
    private static final int port = 99;
    // 维护channel列表,将用户信息和channel做绑定,一个channel代表一个tcp连接
    private static final Map<String, Object> channelMap = new HashMap<>();
    public static void main(String[] args) throws InterruptedException {
        // 创建服务端启动器
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 指定连接接收线程,处理所有用户连接,转给工作线程
        NioEventLoopGroup boss = null;
        // 指定工作线程,处理用户连接
        NioEventLoopGroup worker = null;
        try {
            boss = new NioEventLoopGroup();
            worker = new NioEventLoopGroup();
            serverBootstrap.group(boss, worker); // 绑定线程组
            serverBootstrap.channel(NioServerSocketChannel.class);  // 底层使用nio处理
            serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
                protected void initChannel(NioSocketChannel ch) {
                    // 创建一个心跳检测的handle,服务端创建连接后,5秒内没有收到客户端的心跳就会触发IdleState.READER_IDLE
                    IdleStateHandler idleStateHandler = new IdleStateHandler(5, 0, 0) {
                        // 5秒内没有收到客户端的心跳会触发userEventTriggered方法
                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
                            if (evt instanceof IdleStateEvent) {
                                IdleStateEvent e = (IdleStateEvent) evt;
                                // 检测是读状态就发送pong消息
                                if (e.state() == IdleState.READER_IDLE) {
                                    ByteBuf buffer = Unpooled.buffer();
                                    buffer.writeBytes("pong".getBytes(StandardCharsets.UTF_8));
                                    ctx.channel().writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                                    String id = ctx.channel().id().asLongText();
                                    // 删除channelMap中客户端连接
                                    channelMap.forEach((s, o) -> {
                                        if (s.equals(id)) {
                                            channelMap.remove(s);
                                        }
                                    });
                                }
                            }
                        }
                        // 发生异常时,关闭连接
                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                            log.error(cause.getMessage(), cause);
                            String id = ctx.channel().id().asLongText();
                            channelMap.remove(id);
                            ctx.close();
                        }
                    };
                    // 通过对象实例,而不是new创建,避免大量客户端连接导致浪费空间
                    ch.pipeline().addLast("idleStateHandler", idleStateHandler);
                    // 换行符解码器,指定包与包之间的分隔符是"\n"和"\r\n",避免拆包粘包
                    ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                    // netty日志记录,打印包信息
                    ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                    // 入站字符解码器
                    ch.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                    // 自定义解码器,实现自定义业务逻辑,使用SimpleChannelInboundHandler可以避免ByteBuf的回收问题
                    ch.pipeline().addLast("MyHandle", new SimpleChannelInboundHandler<String>() {
                        // 连接第一次创建会调用这个方法
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            String id = ctx.channel().id().asLongText();
                            log.info("客户端建立连接:{}", id);
                            channelMap.put(id, ctx.channel());
                            ctx.channel().writeAndFlush("this is come from server!");
                            super.channelActive(ctx);
                        }
                        // 获取来自客户端的数据
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, String s) {
                            log.info("收到客户端消息:{}", s);
                            ctx.channel().writeAndFlush("server reply\r\n");
                        }
                    });
                    // 出站字符编码器
                    ch.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync().addListener(future -> {
                if (future.isSuccess()) {
                    log.info("server start up on {}", port);
                }
            });
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 不要忘了在finally中关闭线程组
            if (boss != null) {
                boss.shutdownGracefully();
            }
            if (worker != null) {
                worker.shutdownGracefully();
            }
        }
    }
}

本地测试

image.png


目录
相关文章
|
7月前
|
网络协议 Java Maven
基于Netty实现TCP通信
基于Netty实现TCP通信
109 0
|
7月前
Netty实战: HTTP文件列表服务器
Netty实战: HTTP文件列表服务器
79 0
|
2月前
|
网络协议 前端开发
netty的TCP服务端和客户端实现
本文介绍了使用Netty框架实现TCP服务端和客户端的步骤,包括添加Netty依赖、编写服务端和客户端的代码,涉及NioEventLoopGroup、ServerBootstrap、Bootstrap、ChannelInitializer等核心组件,以及如何启动服务端监听和客户端连接。
209 4
|
7月前
|
网络协议 Java 测试技术
阿里内部Netty实战小册,值得拥有
Netty 是一个高性能的 Java 网络通信框架,简化了网络编程并涵盖了最新的Web技术。它提供了一种抽象,降低了底层复杂性,使得更多开发者能接触网络编程。Netty 因其易用性、高效性和广泛的应用场景受到推崇,适合互联网行业从业者学习,有助于理解和开发基于Netty的系统。免费的《Netty实战小册》详细介绍了Netty的各个方面,包括概念、架构、编解码器、网络协议和实际案例,帮助读者深入理解和应用Netty。如需完整版小册,可点击链接获取。
阿里内部Netty实战小册,值得拥有
|
3月前
|
存储 机器人 Linux
Netty(二)-服务端网络编程常见网络IO模型讲解
Netty(二)-服务端网络编程常见网络IO模型讲解
|
4月前
|
编解码 NoSQL Redis
(十一)Netty实战篇:基于Netty框架打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。
106 3
|
4月前
|
前端开发 网络协议
Netty实战巅峰:从零构建高性能IM即时通讯系统,解锁并发通信新境界
【8月更文挑战第3天】Netty是一款高性能、异步事件驱动的网络框架,适用于开发高并发网络应用,如即时通讯(IM)系统。本文将指导你利用Netty从零构建高性能IM程序,介绍Netty基础及服务器/客户端设计。服务器端使用`ServerBootstrap`启动,客户端通过`Bootstrap`连接服务器。示例展示了简单的服务器启动过程。通过深入学习,可进一步实现用户认证等功能,打造出更完善的IM系统。
188 1
|
4月前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
241 2
|
7月前
|
网络协议 Java 物联网
Spring Boot与Netty打造TCP服务端(解决粘包问题)
Spring Boot与Netty打造TCP服务端(解决粘包问题)
1074 2
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13519 1