Netty实战手册(三)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aiyoyoyo/article/details/78722992

上篇已经讲述了如何搭建基础的服务结构,现在了解下如何完成与客户端的通讯模型。

首先,在HandlerService中,处理接收来自客户端的消息:

@Override
public void receive( ChannelHandlerContext _ctx , Object _obj ) {
	ISupportCommand< ChannelHandlerContext , ByteBuf > cmd = CommonContextHolder.getBean( ISupportCommand.CMD_SERVICE );
	cmd.docommand( _ctx , ( ByteBuf ) _obj );
}

然后在CommandService中处理消息,这里的消息协议是事先与客户端约定的结构、顺序等。当然你可以把ByteBuf替换为Protobuff来使用。这里不详细描述Protobuff的作用和用法了,想了解的人可以自行了解下Protobuff或者Protostuff在Netty中的用法。

@Override
public void docommand( ChannelHandlerContext _ctx , ByteBuf _buf ) {
	int cmd = _buf.readInt();//假设我们只约定了一个int类型的客户端参数
	System.out.println( "CommandService do command: CMD=[" + cmd + "]" );
	//什么事情都没有做,将收到的内容返回客户端。
	ByteBuf buf = _ctx.alloc().buffer();
	buf.writeInt( cmd );
	_ctx.writeAndFlush( buf );
}
基本上,针对协议的处理形式就是这样了。实际应用时,会定义不同的消息内容来完成对应的客户端请求。由于ByteBuf的读写比较繁琐,且不直观,我们会使用上述的Protobuff来代替它来作为消息传递的对象。

在使用JSTS是,会要求你使用自己的解码类来实现针对数据协议的解码粘码工作,这里我没有做相关操作,仅提供了一个消息解码类来完成解码的基本工作:

package com.jees.demo.protos;

import java.nio.ByteOrder;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.jees.jsts.netty.support.*;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;

@Component( value = INettyHandler.NETTY_DECODER ) // 这里会注入自己的解码类到上层的服务中去
@Scope( value = INettyHandler.NETTY_CREATOR ) // 这里是因为Netty的Decoder对象要求每次都必须使用新的对象
public class MessageDecoder extends AbsNettyDecoder {
	// 网络字节序,默认为大端字节序
	public static final int		MAX_FRAME_LENGTH		= 1024 * 4;
	// 消息中长度字段占用的字节数
	public static final int		LENGTH_FIELD_LENGTH		= 4;
	// 消息中长度字段偏移的字节数
	private static final int	LENGTH_FIELD_OFFSET		= 0;
	// 该字段加长度字段等于数据帧的长度
	private static final int	LENGTH_ADJUSTMENT		= 0;
	// 从数据帧中跳过的字节数
	private static final int	INITIAL_BYTES_TO_STRIP	= 0;

	public MessageDecoder() {
		super( ByteOrder.LITTLE_ENDIAN , MAX_FRAME_LENGTH , LENGTH_FIELD_OFFSET , LENGTH_FIELD_LENGTH ,
						LENGTH_ADJUSTMENT , INITIAL_BYTES_TO_STRIP , true );
	}

	@Override
	protected ByteBuf decode( ChannelHandlerContext _ctx , ByteBuf _buf ) throws Exception {
		return _buf;//这里什么解析工作都没有,直接通知给HandlerService处理。其实应该做解码的工作的,否则粘包不能正确处理。
	}
}

下面是完整的客户端代码:

package com.jees.demo.client ;

import java.util.Random;

import io.netty.bootstrap.Bootstrap ;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture ;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption ;
import io.netty.channel.EventLoopGroup ;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup ;
import io.netty.channel.socket.nio.NioSocketChannel ;

public class TestNettyClient {
	private EventLoopGroup	worker ;
	private Bootstrap		booter ;
	private ChannelFuture	future ;

	public TestNettyClient( int _cmd ) {
		try {
			String host = "localhost" ;
			int port = 1000 ;
			worker = new NioEventLoopGroup() ;
			booter = new Bootstrap() ;
			booter.group( worker ).channel( NioSocketChannel.class ).option( ChannelOption.SO_KEEPALIVE , true ).handler( new SimpleChannelInboundHandler< ByteBuf >() {
				@Override
				protected void channelRead0( ChannelHandlerContext ctx , ByteBuf buf ) throws Exception {
					System.out.println( "TestNettyClient read sever msg: MSG=[" + buf.readInt() + "]" );
				}
				
			} );
			future = booter.connect( host , port ).sync() ;
			
			Channel chl = future.channel();
			ByteBuf buf = chl.alloc().buffer();
			buf.writeInt( _cmd );
			chl.writeAndFlush( buf );
			
			future.channel().closeFuture().sync() ;
		} catch ( Exception e ) {
			e.printStackTrace() ;
		} finally {
			worker.shutdownGracefully() ;
		}
	}

	public static void main( String[] args ) {
		new TestNettyClient( new Random().nextInt() );
	}
}
最后,我们将jees-core-dispatcher.xml中的最后一行改为:

<context:component-scan base-package="com.jees.demo.*" /> <!-- 让Spring可以扫描到相关类 -->  
下面是服务器和客户端的消息输出截图:




想了解更多消息的朋友,可以加入QQ群8802330,参与讨论。我会不定期更新相关内容的源代码,供各位学习和使用。

下期我将加入JDBS来进行数据的处理,喜欢的人请关注我的个人博客或者码云:https://gitee.com/aiyoyoyo/或者Github:https://github.com/aiyoyoyo

猜你喜欢

转载自blog.csdn.net/aiyoyoyo/article/details/78722992