netty服务器,客户端的开发

1 篇文章 0 订阅

1.netty

是一种网络传输框架,是对NIO的一个封装,一般用于游戏开发,与此相媲美的是MINA。作者都是同一个人。

2.netty的简单原理



从上图可以很清晰的看到客户端要与服务通信,必须要一个通道与一个端口才能使其相互通信,boos线程池接收数据分配任务给work线程池进行处理业务逻辑

3.客户端与服务器的通道的粘包与拆包的解决方案,
什么是粘包:
一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据。TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU(指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位))的往往小于在应用处理的消息数据,所以就会引发一次接收的数据无法满足消息的需要,导致粘包的存在。处理粘包的唯一方法就是制定应用层的数据通讯协议,通过协议来规范现有接收的数据是否满足消息数据的需要。

解决办法

1、消息定长,报文大小固定长度,不够空格补全,发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。

2、包尾添加特殊分隔符,例如每条报文结束都添加回车换行符(例如FTP协议)或者指定特殊字符作为报文分隔符,接收方通过特殊分隔符切分报文区分。

3、将消息分为消息头和消息体,消息头中包含表示信息的总长度(或者消息体长度)的字段

4、更复杂的自定义应用层协议

下面的则为3的分析




实例如下:
服务器:


package cn.horace.netty.server;

import io.netty.bootstrap.ServerBootstrap;

/**
 * Netty服务器
 * 
 * @author Administrator
 * 
 */
public class NettyServer {

	// 服务器监听的端口
	private static final int PORT = 1588;

	public static void main(String[] args) {

		// 创建服务器引导对象
		ServerBootstrap bootstrap = new ServerBootstrap();

		// 创建“线程池”
		NioEventLoopGroup bossGroup = new NioEventLoopGroup();
		NioEventLoopGroup workGroup = new NioEventLoopGroup();

		try {
			// 设置“线程池”
			bootstrap.group(bossGroup, workGroup);

			// 告诉Netty它也使用NioServerSocketChannel作为连接通道
			bootstrap.channel(NioServerSocketChannel.class);

			// 当客户端向服务器发送数据的时候都会经过这个方法
			bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {

					/**
					 * 解码器
					 * 
					 * 1、maxFrameLength:最大帧长度值,数据包的最大长度
					 * 2、lengthFieldOffset:长度字段的偏移量
					 * 3、lengthFieldLength:长度子字段的长度值 4、lengthAdjustment:长度调节值
					 * 5、initialBytesToStrip:跳过长度字节值
					 * 6、failFast:当数据包超过maxFrameLength值时
					 * ,是否立即抛出异常,true:立即抛出异常,false:把数据接收完毕后在抛出异常
					 */
					socketChannel.pipeline().addLast(
							new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4, false));

					/**
					 * 编码器
					 * 
					 * 1、lengthFieldLength:长度字段的长度值
					 * 2、lengthIncludesLengthFieldLength:如果为true,那么数据包的长度 =
					 * 长度字段的长度 + 实际数据的长度
					 */
					socketChannel.pipeline().addLast(new LengthFieldPrepender(4, 0, false));

					// 数据包的处理器对象
					socketChannel.pipeline().addLast(new ServerMessageHandler());
				}

			});

			// 同步绑定端口,如果绑定端口失败,则会抛出异常
			ChannelFuture future = bootstrap.bind(PORT).sync();

			System.out.println("Server start at " + PORT + ".");

			// 同步监听服务器端口的关闭
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 优雅的释放线程资源,并关闭服务器
			bossGroup.shutdownGracefully();
			workGroup.shutdownGracefully();
		}
	}
}

客户端:

package cn.horace.netty.client;

import io.netty.bootstrap.Bootstrap;

/**
 * Netty客户端
 * 
 * @author Administrator
 * 
 */
public class NettyClient {

	// 服务器监听的端口
	private static final int PORT = 1588;
	private static final String HOST = "127.0.0.1";

	public static void main(String[] args) {

		// 创建客户端引导对象
		Bootstrap bootstrap = new Bootstrap();

		// 创建“线程池”
		NioEventLoopGroup group = new NioEventLoopGroup();

		try {
			// 设置“线程池”
			bootstrap.group(group);

			// 告诉Netty它也使用NioSocketChannel作为连接通道
			bootstrap.channel(NioSocketChannel.class);

			// 当客户端向服务器发送数据的时候都会经过这个方法
			bootstrap.handler(new ChannelInitializer<SocketChannel>() {

				// 这个方法一般是用于做数据包的解码与编码操作
				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {

					/**
					 * 解码器
					 * 
					 * 1、maxFrameLength:最大帧长度值,数据包的最大长度
					 * 2、lengthFieldOffset:长度字段的偏移量
					 * 3、lengthFieldLength:长度子字段的长度值 4、lengthAdjustment:长度调节值
					 * 5、initialBytesToStrip:跳过长度字节值
					 * 6、failFast:当数据包超过maxFrameLength值时
					 * ,是否立即抛出异常,true:立即抛出异常,false:把数据接收完毕后在抛出异常
					 */
					socketChannel.pipeline().addLast(
							new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4, false));

					/**
					 * 编码器
					 * 
					 * 1、lengthFieldLength:长度字段的长度值
					 * 2、lengthIncludesLengthFieldLength:如果为true,那么数据包的长度 =
					 * 长度字段的长度 + 实际数据的长度
					 */
					socketChannel.pipeline().addLast(new LengthFieldPrepender(4, 0, false));

					// 数据包的处理器对象
					socketChannel.pipeline().addLast(new ClientMessageHandler());
				}
			});

			// 连接服务器
			ChannelFuture future = bootstrap.connect(new InetSocketAddress(HOST, PORT)).sync();

			System.out.println("Conennect server success.");
			
			// 同步监听服务器端口的关闭
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 优雅的释放线程资源,并关闭客户端
			group.shutdownGracefully();
		}
	}
}

注意:别忘了添加netty-all-4.0.31.Final.jar哦,没有jar可到netty官网http://netty.io/下载,或者前往http://mvnrepository.com/search?q=netty下载




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

家有小辉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值