netty实现TCP通信

目录

引入netty包

 启动服务并监听端口

 配置拦截器

 客户端加入、退出、发送消息处理程序

springboot 项目可设置启动服务时启动netty服务

 模拟客户端测试


引入netty包

<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.25.Final</version>
            <scope>compile</scope>
        </dependency>

 启动服务并监听端口


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

@Component
@Slf4j
public class NettyServer {

    public static void main(String[] args){
        String url = "127.0.0.1";
        int port = 7000;
        InetSocketAddress address =new InetSocketAddress(url,port);
        new NettyServer().start(address);
    }

    public void start(InetSocketAddress address){
        /**
         * 两个独立的Reactor线程池
         * 一个用于接收客户端的TCP连接
         * 另一个用于处理I/O相关的读写操作,或者执行系统Task、定时任务Task等。
         */
        EventLoopGroup bossGroup =new NioEventLoopGroup(1);
        EventLoopGroup worksGroup =new NioEventLoopGroup();
        try {
            //一个对服务端做配置和启动的类
            ServerBootstrap bootstrap =new ServerBootstrap()//类似构造器
                    .group(bossGroup,worksGroup)//组的概念
                    .channel(NioServerSocketChannel.class)//NIO类的SocketServer通道
                    .localAddress(address)//服务地址
                    .childHandler(new ServerChannelInitializer())//拦截器实例化
                    .option(ChannelOption.SO_BACKLOG,128) //父渠道日志配置
                    .childOption(ChannelOption.SO_KEEPALIVE,true);//子渠道配置
            //绑定端口,开始接收进来的连接
            ChannelFuture future =bootstrap.bind(address).sync();
            log.info("服务已启动,端口为"+address.getPort());
            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
            bossGroup.shutdownGracefully();
            worksGroup.shutdownGracefully();
        }
    }

}

 配置拦截器

import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        channel.pipeline().addLast("decoder",new StringDecoder(CharsetUtil.UTF_8));
        channel.pipeline().addLast("encoder",new StringEncoder(CharsetUtil.UTF_8));
        channel.pipeline().addLast(new ServerHandlers());

    }
}

 客户端加入、退出、发送消息处理程序


import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ServerHandlers extends ChannelInboundHandlerAdapter {
    /**
     * 创建一个静态组
     */
    private static ChannelGroup channels =new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    @Override
    public void handlerAdded(ChannelHandlerContext ctx){
        //加入ChannelGroup
        channels.add(ctx.channel());
        log.info(ctx.channel().id()+"的设备加入群聊"+"Online:"+channels.size());
    }

    @Override
    public  void handlerRemoved(ChannelHandlerContext context){
        log.info(context.channel().id()+"的设备退出群聊"+"Online:"+channels.size());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //打印消息然后群发
        log.info(msg.toString());
        for (Channel channel:channels){
            log.info("群发消息,向channelid==="+channel.id().asShortText()+" 发送消息");
            channel.writeAndFlush(msg.toString());
        }
    }

    /**
     * 设备异常关闭
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause)throws Exception{
        log.info(ctx.channel().id()+"的设备出错"+"Online:"+channels.size());
        ctx.close();
    }
}

springboot 项目可设置启动服务时启动netty服务

application中新增如下代码

@Override
    public void run(String... args) throws Exception {
        String url = serverSocketHost;
        int port = nettyPort;
        InetSocketAddress address = new InetSocketAddress(url, port);
        new NettyServer().start(address);
    }

 模拟客户端测试

可找TCP相关的工具,例如:TCPUDPDbg,百度自行下载

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哎呦喂哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值