Netty实现长连接简单例子

Netty实现长连接的简单例子

服务端

NettyServerBootstrap提供长连接服务

public class NettyServerBootstrap {

	private static final Log log = LogFactory.getLog(NettyServerBootstrap.class);
	private Integer port;
	private SocketChannel socketChannel;
	public NettyServerBootstrap(Integer port) throws Exception {
		this.port = port;
		bind(port);
	}
	public Integer getPort() {
		return port;
	}
	public void setPort(Integer port) {
		this.port = port;
	}
	public SocketChannel getSocketChannel() {
		return socketChannel;
	}
	public void setSocketChannel(SocketChannel socketChannel) {
		this.socketChannel = socketChannel;
	}
	private void bind(int serverPort) throws Exception {
		// 连接处理group
		EventLoopGroup boss = new NioEventLoopGroup();
		// 事件处理group
		EventLoopGroup worker = new NioEventLoopGroup();
		ServerBootstrap bootstrap = new ServerBootstrap();
		// 绑定处理group
		bootstrap.group(boss, worker);
		bootstrap.channel(NioServerSocketChannel.class);
		// 保持连接数
		bootstrap.option(ChannelOption.SO_BACKLOG, 1024 * 1024);
		// 有数据立即发送
		bootstrap.option(ChannelOption.TCP_NODELAY, true);
		// 保持连接
		bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
       // 处理新连接
		bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel sc) throws Exception {
				// 增加任务处理
				ChannelPipeline p = sc.pipeline();
				p.addLast(new MessageDecoder(), new MessageEncoder(), new NettyServerHandler());
			 }
		});

		ChannelFuture f = bootstrap.bind(serverPort).sync();
		if (f.isSuccess()) {
			log.info("long connection started success");
		} else {
			log.error("long connection started fail");
		}
	}
}

启动服务,监听9999端口

public static void main(String[] args) {
		try {
			new NettyServerBootstrap(9999);
		} catch (Exception e) {
			
			e.printStackTrace();
		}
}

定义客户端服务端通信协议,一下是一个简单的通信协议

协议分为headerbody两部分,都是用网络字节序(BIG ENDIAN

header{

magic 32bit;  //校验用固定值0x0CAFFEE0

version 8bit;  //版本号

type 8bit;     //类型,请求或者响应

seq 32bit;     //序号标记一对请求响应

length 32bit;  //body长度

}

body{

 

}

根据通信协议,编写解码器和编码器

解码器MessageDecoder

public class MessageDecoder extends ByteToMessageDecoder {
	private static final int MAGIC_NUMBER = 0x0CAFFEE0;
	public MessageDecoder() {

	}
	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		if (in.readableBytes() < 14) {
			return;
		}
		// 标记开始读取位置
		in.markReaderIndex();

		int magic_number = in.readInt();

		if (MAGIC_NUMBER != magic_number) {
			ctx.close();
			return;
		}

		@SuppressWarnings("unused")
		byte version = in.readByte();

		byte type = in.readByte();
		int squence = in.readInt();
		int length = in.readInt();

		if (length < 0) {
			ctx.close();
			return;
		}

		if (in.readableBytes() < length) {
			// 重置到开始读取位置
			in.resetReaderIndex();
			return;
		}

		byte[] body = new byte[length];
		in.readBytes(body);

		RequestInfoVO req = new RequestInfoVO();
		req.setBody(new String(body, "utf-8"));
		req.setType(type);
		req.setSequence(squence);
		out.add(req);
	}
}

编码器MessageEncoder

public class MessageEncoder extends MessageToByteEncoder<RequestInfoVO> {

	private static final String DEFAULT_ENCODE = "utf-8";

	private static final int MAGIC_NUMBER = 0x0CAFFEE0;

	public MessageEncoder() {
	}

	@Override
	protected void encode(ChannelHandlerContext ctx, RequestInfoVO msg, ByteBuf out) throws Exception {

		@SuppressWarnings("resource")
		ByteBufOutputStream writer = new ByteBufOutputStream(out);
		byte[] body = null;

		if (null != msg && null != msg.getBody() && "" != msg.getBody()) {
			body = msg.getBody().getBytes(DEFAULT_ENCODE);
		}

		writer.writeInt(MAGIC_NUMBER);

		writer.writeByte(1);

		writer.writeByte(msg.getType());

		writer.writeInt(msg.getSequence());

		if (null == body || 0 == body.length) {
			writer.writeInt(0);
		} else {
			writer.writeInt(body.length);
			writer.write(body);
		}
	}

}

服务端事件处理NettyServerHandler

@Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<RequestInfoVO> {
	private static final Log log = LogFactory.getLog(NettyServerHandler.class);

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, RequestInfoVO msg) throws Exception {
		//
	}

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

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		
	}


	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
		
	}

}

客户端

NettyClientBootstrap连接长连接服务

public class NettyClientBootstrap {
	private int port;
	private String host;
	private SocketChannel socketChannel;
	public NettyClientBootstrap(int port, String host) throws Exception {
		this.host = host;
		this.port = port;
		start();
	}
	private void start() throws Exception {
		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
		Bootstrap bootstrap = new Bootstrap();
		bootstrap.channel(NioSocketChannel.class);
		bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
		bootstrap.option(ChannelOption.TCP_NODELAY, true);
		bootstrap.group(eventLoopGroup);
		bootstrap.remoteAddress(this.host, this.port);
		bootstrap.handler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel socketChannel) throws Exception {
				socketChannel.pipeline().addLast(new MessageDecoder(), new MessageEncoder(), new NettyClientHandler());
			}
		});
		ChannelFuture future = bootstrap.connect(this.host, this.port).sync();
		if (future.isSuccess()) {
			socketChannel = (SocketChannel) future.channel();
			System.out.println("connect server  success|");
		}
	}
	public int getPort() {
		return this.port;
	}
	public void setPort(int port) {
		this.port = port;
	}

	public SocketChannel getSocketChannel() {
		return socketChannel;
	}
	public void setSocketChannel(SocketChannel socketChannel) {
		this.socketChannel = socketChannel;
	}
	public String getHost() {
		return host;
	}
	public void setHost(String host) {
		this.host = host;
	}
}

初始化客户端

public static void main(String[] args) throws Exception {
		NettyClientBootstrap bootstrap = new NettyClientBootstrap(9999, "127.0.0.1");
		int i = 1;

		while (true) {
			TimeUnit.SECONDS.sleep(2);
			RequestInfoVO req = new RequestInfoVO();
			req.setSequence(123456);
			req.setType((byte) 1);
			req.setSequence(0);
			req.setBody(String.valueOf((new Date()).getTime()));
			bootstrap.getSocketChannel().writeAndFlush(req);
			i++;
		}
	}

根据协议编写编码器,解码器,同服务端编码器、解码器

客户端事件处理

public class NettyClientHandler extends SimpleChannelInboundHandler<RequestInfoVO> {

	@Override
	protected void messageReceived(ChannelHandlerContext ctx, RequestInfoVO msg) throws Exception {
		System.out.println(msg.getBody());
		RequestInfoVO req = new RequestInfoVO();
		req.setSequence(msg.getSequence());
		req.setType(msg.getType());
		if (2 == msg.getType()) {
			req.setBody("client");
			ctx.channel().writeAndFlush(req);
		} else if (3 == msg.getType()) {
			req.setBody("zpksb");
			ctx.channel().writeAndFlush(req);
		}

	}

}


至此,实现了简单的客户端服务端长连接。







  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
Netty是一个基于Java的网络编程框架,它提供了一种简单且高性能的方式来实现WebSocket协议。 要使用Netty实现WebSocket,可以按照以下步骤进行操作: 1. 创建一个新的Netty项目,并添加Netty的依赖。 2. 创建一个WebSocket服务器类,该类需要继承自`io.netty.channel.SimpleChannelInboundHandler`。 3. 在服务器类中,重写`channelRead0`方法,处理接收到的WebSocket消息。 4. 在服务器类中,重写`channelActive`和`channelInactive`方法,处理WebSocket连接的打开和关闭事件。 5. 在服务器类中,重写`exceptionCaught`方法,处理异常情况。 6. 创建一个启动类,在其中创建并配置一个`io.netty.bootstrap.ServerBootstrap`实例。 7. 在启动类中,绑定服务器端口并启动服务器。 下面是一个简单的示例代码,演示了如何使用Netty实现WebSocket服务器: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; 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.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; public class WebSocketServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new HttpServerCodec()); ch.pipeline().addLast(new HttpObjectAggregator(65536)); ch.pipeline().addLast(new WebSocketServerProtocolHandler("/websocket")); ch.pipeline().addLast(new WebSocketServerHandler()); } }); ChannelFuture future = bootstrap.bind(8080).sync(); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } ``` 在上面的代码中,`WebSocketServerHandler`是自定义的处理器,用于处理WebSocket消息。你可以根据自己的需求来实现该处理器。 请注意,这只是一个简单的示例,实际的WebSocket服务器可能需要更复杂的处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值