news 2026/4/15 16:24:36

基于Netty的TCP协议的Socket服务端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Netty的TCP协议的Socket服务端

01 引言

上一节分享Websocket独立部署的一个设计思路,我们今天接着聊一下基于Netty的TCP协议的Socket服务端如何搭建。这个对于熟悉的人可能很简单,但是对于新手或者不常用的开发者来说,可能一头雾水。

小编在初次使用Socket的时候,都是度娘一大堆,然后抄抄抄,完成自己的任务。至于为什么这么做,完全不知道。这一节将自己的理解分享并记录下来,以备不时之需。

02 服务端案例

2.1 代码展示

publicvoidstart(){// 创建线程组EventLoopGroupbossGroup=newNioEventLoopGroup(1);EventLoopGroupworkGroup=newNioEventLoopGroup(5);try{// 服务端类ServerBootstrapserverBootstrap=newServerBootstrap();// 添加组serverBootstrap.group(bossGroup,workGroup);// 设置NioServerSocketChannel通道serverBootstrap.channel(NioServerSocketChannel.class);// 连接队列大小serverBootstrap.option(ChannelOption.SO_BACKLOG,1024)// 保持连接serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);serverBootstrap.childHandler(newChannelInitializer<SocketChannel>(){@OverrideprotectedvoidinitChannel(SocketChannelsocketChannel)throwsException{// 设置处理器链,依次执行ChannelPipelinepipeline=socketChannel.pipeline();pipeline.addLast(newDelimiterBasedFrameDecoder(2048,Unpooled.copiedBuffer("_".getBytes())));pipeline.addLast(newStringDecoder(StandardCharsets.UTF_8));pipeline.addLast(newStringEncoder(StandardCharsets.UTF_8));// 自定义的handler,处理业务逻辑pipeline.addLast(newBusinessHandler<>());}});// 配置完成,开始绑定server,通过调用sync同步方法阻塞直到绑定成功ChannelFuturechannelFuture=serverBootstrap.bind(9091).sync();log.info("Server started and listen on:{}",channelFuture.channel().localAddress());// 对关闭通道进行监听channelFuture.channel().closeFuture().sync();}catch(Exceptione){log.error("信息异常:",e);}finally{bossGroup.close();workGroup.close();}}

2.2 创建线程组

// 创建线程组EventLoopGroupbossGroup=newNioEventLoopGroup(1);EventLoopGroupworkGroup=newNioEventLoopGroup(5);

EventLoopGroup就是一个线程池。在NettySocket中需要两个不同的线程池,分别处理不同的任务。其中bossGroup用来接收客户端连接,通常设置1个线程,而workGroup用来处理I/O操作和业务逻辑,可以根据CPU的核心数指定。

2.3 创建服务端

// 服务端类ServerBootstrapbootstrap=newServerBootstrap();// 添加组serverBootstrap.group(bossGroup,workGroup);// 设置NioServerSocketChannel通道serverBootstrap.channel(NioServerSocketChannel.class);// 连接队列大小serverBootstrap.option(ChannelOption.SO_BACKLOG,1024)// 保持连接serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);

服务端引导类创建完成之后,需要设置参数:

  • group():添加线程池组,第一个参数为bossGroup,第二个是workGroup
  • channel():设置NioServerSocketChannel通道
  • option():配置服务端监听的ServerSocketChannel
  • childOption():配置客户端连接的SocketChannel

所以这里的ChannelOption.SO_BACKLOG只能设置在option中,用来指定服务端接收的任务最大队列。ChannelOption.SO_KEEPALIVE用来TCP保活机制,检测死连接,是针对客户端的连接,所以需要设置在childOption上。

ChannelOption.SO_KEEPALIVE也可以不同设置,采用心跳机制来保活。其使用有一定的局限性,通常都会通过心跳机制来代替。

2.4 设置处理链

serverBootstrap.childHandler(newChannelInitializer<SocketChannel>(){@OverrideprotectedvoidinitChannel(SocketChannelsocketChannel)throwsException{// 设置处理器链,依次执行ChannelPipelinepipeline=socketChannel.pipeline();pipeline.addLast("...");pipeline.addLast("...");}});

采用责任链模式,每个处理器处理特定任务,依次执行。里面具体的Handler单独说明。

2.5 绑定端口,同步阻塞

// 配置完成,开始绑定server,通过调用sync同步方法阻塞直到绑定成功ChannelFuturechannelFuture=serverBootstrap.bind(9091).sync();// 对关闭通道进行监听channelFuture.channel().closeFuture().sync();

当前服务端绑定一个端口,客户端就可以通过当前端口连接,并同步阻塞,等待端口绑定成功。最后同步阻塞等待通过关闭。

03 消息处理

消息的处理是接受和推送消息重要部分。Netty框架提供了丰富的处理器,我们可以选择适合自己的处理器。处理器都是实现io.netty.channel.ChannelInboundHandler接口

3.1 框架自带编解码器

Netty框架下的Socket数据传输,默认都是ByteBuf(字节缓冲)。我们使用的时候自然想通过常用的字符串传输,而Netty自然帮我们提供了字符串相关的编解码处理器。

  • io.netty.handler.codec.string.StringDecoder
  • io.netty.handler.codec.string.StringEncoder

通过源码我们可以看到注释:

StringDecoder是将ByteBuf转成字符串的解码器,但是在处理之前必须使用ByteToMessageDecoder先解码,子类包括:

  • io.netty.handler.codec.DelimiterBasedFrameDecoder:分隔符分割
  • io.netty.handler.codec.FixedLengthFrameDecoder:固定长度分割
  • io.netty.handler.codec.LengthFieldBasedFrameDecoder:按照字段长度分割
  • io.netty.handler.codec.LineBasedFrameDecoder:按行分割

这几种方式都是有效防止拆包、粘包的方法。

按照注释的案例,我们就可以配置。而StringEncoder是用来发送消息的解码器,用来将字符串转成ByteBuf

我们这里采用分隔符的方式分割:

pipeline.addLast(newDelimiterBasedFrameDecoder(2048,Unpooled.copiedBuffer("_".getBytes())));pipeline.addLast(newStringDecoder(StandardCharsets.UTF_8));pipeline.addLast(newStringEncoder(StandardCharsets.UTF_8));

而其中DelimiterBasedFrameDecodermaxFrameLength参数用来控制接收消息的最大字节大小,超过就会异常。

3.2 自定义业务处理器

自定义业务处理器是用来处理客户端连接以及消息的。

@Slf4jpublicclassBusinessHandlerextendsSimpleChannelInboundHandler{@OverridepublicvoidhandlerAdded(ChannelHandlerContextctx)throwsException{// 建立客户端Channelchannel=ctx.channel();log.info("Socket客户端建立连接:channelId={}",channel.id());}@OverridepublicvoidhandlerRemoved(ChannelHandlerContextctx)throwsException{// 断开链接Channelchannel=ctx.channel();log.info("Socket客户端断开连接:channelId={}",channel.id());}@OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,Objectmsg)throwsException{// 接受消息Channelchannel=ctx.channel();log.info("Socket收到来自通道channelId[{}]发送的消息:{}",channel.id(),msg);// 通过WebSocket将方法发送给客户端channel.writeAndFlush(msg+"789_000");}@OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause)throwsException{log.info("异常:",cause);}}

handlerAdded()

客户端建立连接之后会触发该方法。可以通过ctx.channel()获取来连接的通道(客户端)。连接的通常可以通过io.netty.channel.group.ChannelGroup收集。

ChannelGroupchannelGroup=newDefaultChannelGroup(GlobalEventExecutor.INSTANCE)channelGroup.add(channel);

向客户端发送消息时,可以通过channelGroup.writeAndFlush()统一给客户端发送消息。

handlerRemoved()

客户端断开连接的时触发,可以通过channelGroup.remove(channel)移除已经关闭的客户端通道

channelRead0()

接收客户端消息的重要方法,通过channel.writeAndFlush()可以直接向客户端发送消息

exceptionCaught()

处理异常的方法

3.3 客户端测试

从图上可以看出,介绍的方法都被触发了。

从图可以看出客户端的也接收到服务端的消息了。

注意

客户端发送的消息:foo test…_

服务端发送的消息:foo test…789_000

客户端接受的消息:foo test…789

客户端和服务端接收到的消息都通过_截断的

04 小结

简单的服务端搭建就已经好了,但是实际应用的时候,还需要考虑心跳机制、以及无效客户端的清理等。TCP协议服务端的介绍就到这里,客户端我们下一期介绍。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 14:44:48

Llama Factory性能优化:如何利用云端GPU加速微调过程

Llama Factory性能优化&#xff1a;如何利用云端GPU加速微调过程 在大模型微调实践中&#xff0c;许多数据团队都面临一个共同痛点&#xff1a;模型微调耗时过长&#xff0c;严重拖慢项目迭代速度。本文将介绍如何通过Llama Factory结合云端GPU资源&#xff0c;显著提升微调效率…

作者头像 李华
网站建设 2026/3/31 3:19:26

告别if-else!用Java枚举提升代码效率的5种方式

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 请用Java实现两个功能相同的版本&#xff1a;1.使用传统的if-else实现状态机 2.使用枚举实现相同的状态机。要求对比展示两种实现的代码量、可读性和性能差异。包含性能测试代码&a…

作者头像 李华
网站建设 2026/4/10 2:39:04

新闻媒体素材管理:老报纸数字化OCR实施方案

新闻媒体素材管理&#xff1a;老报纸数字化OCR实施方案 &#x1f4f0; 老报纸数字化的挑战与OCR技术价值 在新闻媒体机构的历史档案中&#xff0c;大量珍贵信息以纸质老报纸的形式封存。这些资料承载着时代记忆&#xff0c;但受限于物理形态&#xff0c;难以检索、易损毁、不便…

作者头像 李华
网站建设 2026/4/13 9:26:34

3C一体工具箱安卓版(手机维护工具箱)

3C All-in-One Toolbox是一款功能强大的安卓手机维护工具软件&#xff0c;可以帮助用户清理手机内存、加速手机运行、管理应用程序、监控手机性能等。 软件功能 清理手机内存和垃圾文件&#xff1a;可以一键清理手机缓存、残留文件、广告文件等&#xff0c;释放手机存储空间。…

作者头像 李华
网站建设 2026/4/11 1:39:31

Stable Diffusion WebUI完全指南:从零开始的AI图像生成之旅

Stable Diffusion WebUI完全指南&#xff1a;从零开始的AI图像生成之旅 【免费下载链接】stable-diffusion-webui AUTOMATIC1111/stable-diffusion-webui - 一个为Stable Diffusion模型提供的Web界面&#xff0c;使用Gradio库实现&#xff0c;允许用户通过Web界面使用Stable Di…

作者头像 李华
网站建设 2026/4/5 1:26:44

ln -s软链接技巧:管理多个语音模型版本

ln -s软链接技巧&#xff1a;管理多个语音模型版本 在语音合成系统的开发与部署过程中&#xff0c;模型版本管理是一个常被忽视但极其关键的工程实践。尤其是在基于 ModelScope 的 Sambert-Hifigan 这类多模块深度学习系统中&#xff0c;频繁的模型迭代、A/B 测试、回滚需求使得…

作者头像 李华