netty框架做游戏netty 服务器框架搭建怎么样

Java游戏服务器-Netty自动重连与会话管理 - 推酷
Java游戏服务器-Netty自动重连与会话管理
网游少不了网络通信,不像写C++时自己造轮子,Java服务器使用Netty。Netty做了很多工作,使编写网络程序变得轻松简单。灵活利用这些基础设施,以实现我们的需求。
其中一个需求是自动重连。自动重连有两种应用场景:
开始连接时,对端尚未开启
连接中途断开
在有多个服务器(比如LoginServer和GameServer等)时,这样就不用考虑服务器启动顺序。有需求就需要有解决方案,其实很简单,Netty已经提供,如下:
ctx.channel().eventLoop().schedule(() -& tryConnect(), reconnectInterval, TimeUnit.SECONDS);
tryConnect是实际执行连接的方法,后面两个参数表示每隔
reconnectInterval
秒重连一次即执行
tryConnect
,而对应上述两种应用场景的分别是connect失败和channel inactive时,详见后面代码。
自动重连解决后,还有一个问题是如何管理连接。Netty使用Channel来抽象一个连接,但实际开发时,通常逻辑上会有一个
会话(Session)
对象用来表示对端,可以在其上添加各种逻辑属性方法等,以及收发网络消息。这样一个Channel就需要对应一个Session,且方便互相索引。
首先考虑如何创建这个Session。
为了方便Netty使用和复用,我抽象了一个TcpServer/TcpClient类分别表示服务器和客户端。理想情况是 TcpServer和TcpClient合并为一个,不同行为由Session来决定。但因为Netty的服务器和客户端分别使用ServerBootstrap和Bootstrap,其分别包含bind和connect,这个想法未能实现。
Session有两种,ListenSession负责监听连接请求,TransmitSession负责传输数据。在实际应用中,有这么一种需求,比如GameServer主动连接LoginServer,这时GameServer即作为client端。在连接成功时,需要GameServer主动发个注册消息给LoginServer,LoginServer籍此得知是哪个服务器组。此时,GameServer可能同时会以Client身份连接另一个服务器比如Gateway而且同样要发消息。那么作为client端主动连接的TransmitSession最好细化,需要包含要连接的主机地址、端口和重连时间等信息,也需要在Active时发送不同消息,而Server端TransmitSession并不需要。所以设计上TransmitSession又分为ClientSession和ServerSession。SeverSession由TcpServer在建立连接时自动创建,而ListenSession和ClientSession则由使用者自行创建并交由TcpServer/TcpClient管理。
接口如下:
public abstract class ListenSession {
private boolean working =
private int localPort = 0;
private int relistenInterval = 10;
public abstract ServerSession createServerSession();
public abstract class TransmitSession {
protected Channel channel =
protected boolean working =
public abstract void onActive() throws E
public abstract void onInactive() throws E
public abstract void onException() throws E
public abstract void onReceive(Object data) throws E
public abstract void send(Object data);
public abstract class ClientSession extends TransmitSession {
private String remoteHost = &&;
private int remotePort = 0;
private int reconnectInterval = 10;
其次考虑如何管理Channel和Session的对应关系。除了使用一个类似HashMap\
的容器来管理外,一个更自然的想法是直接把Session记录在Channel上就好了,这样就省去了每次查找的开销。Netty已经提供了,即Channel的AttrMap。这里或许有疑问的是,client端connect成功的Channel和Active/Inactive时的Channel是同一个,所以可以方便放置/取出数据。而server端bind成功的Channel放置的是ListenSession,Active/Inactive时的Channel却是一个新的,并非bind的Channel,怎么取出之前放入的ListenSession来呢?Netty也想到了,所以提供了Channel.parent()方法,每一个Active时的Channel是由bind时的Channel创建的,后者就是前者的parent。
综上,TcpServer示例如下:
public class TcpServer {
private final AttributeKey&ListenSession& LISTENSESSIONKEY = AttributeKey.valueOf(&LISTENSESSIONKEY&);
private final AttributeKey&ServerSession& SERVERSESSIONKEY = AttributeKey.valueOf(&SERVERSESSIONKEY&);
private final ServerBootstrap bootstrap = new ServerBootstrap();
private EventLoopGroup bossGroup =
private EventLoopGroup workerGroup =
private ArrayList&ListenSession& listenSessions = new ArrayList&ListenSession&();
private void start() {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup(4);
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer&SocketChannel&() {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(&encode&, new ObjectEncoder());
pipeline.addLast(&decode&, new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(workerGroup, new ChannelInboundHandlerAdapter() {
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ListenSession listenSession = ctx.channel().parent().attr(LISTENSESSIONKEY).get();
ServerSession serverSession = listenSession.createServerSession();
ctx.channel().attr(SERVERSESSIONKEY).set(serverSession);
serverSession.setChannel(ctx.channel());
serverSession.onActive();
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ServerSession serverSession = ctx.channel().attr(SERVERSESSIONKEY).get();
serverSession.onInactive();
private void tryListen(ListenSession listenSession) {
if (!listenSession.isWorking()) {
final int port = listenSession.getLocalPort();
final int interval = listenSession.getRelistenInterval();
ChannelFuture f = bootstrap.bind(port);
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture f) throws Exception {
if (f.isSuccess()) {
f.channel().attr(LISTENSESSIONKEY).set(listenSession);
f.channel().eventLoop().schedule(() -& tryListen(listenSession), interval, TimeUnit.SECONDS);
如果监听失败则隔
秒重试,新连接建立时创建ServerSession关联该Channel。
TcpClient的实现大同小异,不同点在于需要在Channel Inactive时执行重连:
public class TcpClient {
private final AttributeKey&ClientSession& SESSIONKEY = AttributeKey.valueOf(&SESSIONKEY&);
private final Bootstrap bootstrap = new Bootstrap();
private EventLoopGroup workerGroup =
private ArrayList&ClientSession& clientSessions = new ArrayList&ClientSession&();
private void start() {
workerGroup = new NioEventLoopGroup();
bootstrap.group(workerGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer&SocketChannel&() {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(&encode&, new ObjectEncoder());
pipeline.addLast(&decode&, new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ChannelInboundHandlerAdapter() {
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ClientSession clientSession = ctx.channel().attr(SESSIONKEY).get();
clientSession.setChannel(ctx.channel());
clientSession.onActive();
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ClientSession clientSession = ctx.channel().attr(SESSIONKEY).get();
clientSession.onInactive();
final int interval = clientSession.getReconnectInterval();
ctx.channel().eventLoop().schedule(() -& tryConnect(clientSession), interval, TimeUnit.SECONDS);
private void tryConnect(ClientSession clientSession) {
if (!clientSession.isWorking()) {
final String host = clientSession.getRemoteHost();
final int port = clientSession.getRemotePort();
final int interval = clientSession.getReconnectInterval();
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture f) throws Exception {
if (f.isSuccess()) {
f.channel().attr(SESSIONKEY).set(clientSession);
f.channel().eventLoop().schedule(() -& tryConnect(clientSession), interval, TimeUnit.SECONDS);
如果需要监听多个端口或连接多个目的主机,只需要创建多个ClientSession/ListenSession即可。如:
private TcpServer tcpServer = new TcpServer();
private LSServer lsServer = new LSServer();
private LSClient lsClient = new LSClient();
lsServer.setLocalPort(30001);
lsServer.setRelistenInterval(10);
tcpServer.attach(lsServer);
lsClient.setLocalPort(40001);
lsClient.setRelistenInterval(10);
tcpServer.attach(lsClient);
另外值得一提的是网上很多例子,都会在bind端口后,调用如下代码:
f.channel().closeFuture().sync();
这会阻塞当前线程,其实就是在当前线程做main loop。而实际游戏服务器中,通常main线程做逻辑线程,逻辑线程需要自己tick,也就是自定义main loop,我们在其中执行一些每帧更新的逻辑。所以并不需要上面这种方式。
公共库仓库:
服务器示例仓库:
新建QQ交流群:
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致所谓磨刀不误砍柴工,所以在搭建netty游戏服务器之前,我们先要把要准备的东西做好。
首先进入netty的官网下载最新版本的netty的jar包,http://netty.io/downloads.html,这里我下载的是&版本的。
打开压缩包,找到all-in-one下面的netty-5.0.0.Alpha2.jar包。
打开我们的eclipse我们神圣的编辑器,然后新建一个File,取名叫lib,专门存放第三方的jar。
然后把之前的netty的jar拖到里面,然后再配置路径。
add jars吧这个包添加到路径里面。
ok,往事具备。接着我们开始netty编程之旅。先声明一点,读者需要对netty有所了解,不然可能看不懂我写的代码。
首先,我们先打个package,取名为com.netty.server,在包里面我们新建一个类GameServer,就是我们的服务器的主入口。
public class GameServer {
public void bind(int port) throws Exception
EventLoopGroup bossGroup = new NioEventLoopGroup();//线程组
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();//server启动管理配置
b.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)//最大客户端连接数为1024
.childHandler(new ChannelInitializer&SocketChannel&() {
protected void initChannel(SocketChannel ch) throws Exception {
//这里我们先不写代码,这里主要是添加业务处理handler
ChannelFuture f = b.bind(port).sync();
if (f.isSuccess())
System.out.println("Server starts success at port:" + port);
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
public static void main(String[] args) throws Exception
int port = 8080;
new GameServer().bind(port);
运行,就可以发现服务启动了。
阅读(...) 评论()后使用快捷导航没有帐号?
查看: 594|回复: 6
netty 能做什么
注册会员, 积分 91, 距离下一级还需 109 积分
论坛徽章:6
netty是优秀的网络应用程序框架,关键词是NIO和异步。它提供了对JAVA网络编程API的封装,屏蔽了繁杂的编程细节,让开发者可以更加专注于业务逻辑的实现。很多中间件都是基于netty来实现的,你可以用来实现一个web容器,也能写一个游戏服务器。学习netty能够让你更加熟悉网络编程,对个人好处还是比较大的。至于学习时间,看个人而言,有JAVA NIO编程经验和网络编程经验上手会更加快。
1. netty是非阻塞事件驱动框架, 并结合线程组(group)的概念,可以很好的支持高并发,慢连接的场景。
2. 编程接口非常容易,并且也较好的解决了TCP粘包/拆包的问题.netty提供了自己的ByteBuf和channel,相比于jdk的ByteBuffer和channel来说更简便灵活操作, 并提供了pipeline的概念,并针对每个contextHandler都可以由用户定义, 方便直接.
3. 有一些web框架已经开始直接使用netty做为底层通信服务,诸如play. 这样play就不用依赖于容器去进行部署,在没有nginx做反向代理的情况下也能支持高并发.编解码器可以随意扩展,今天是个web,明天就可以是一个ftp或email服务器,个人觉得比较灵活。
新手上路, 积分 25, 距离下一级还需 25 积分
论坛徽章:4
可以做游戏高性能通信模块,可以做socket服务器等等
高级会员, 积分 735, 距离下一级还需 265 积分
论坛徽章:21
netty是优秀的JAVA网络应用程序框架,关键词是NIO和异步
高级会员, 积分 578, 距离下一级还需 422 积分
论坛徽章:7
不错了 学习了 谢谢~~
论坛徽章:34
这个不错,需要学习一下。
新手上路, 积分 7, 距离下一级还需 43 积分
论坛徽章:1
我只能说Netty是一个NIO的框架,可以用于开发分布式的Java程序。具体能做什么,各位可以尽量发挥想象。
注册会员, 积分 119, 距离下一级还需 81 积分
论坛徽章:1
游戏,收集游戏可以使用netty下次自动登录
现在的位置:
& 综合 & 正文
Netty基础介绍与框架搭建
问题所在:
目前为止,互联网上的通讯都是通过已有的应用或者软件库来实现。例如,我们最常使用的就是利用HTTP协议客户端(浏览器或者其他)从远程服务器上获取信息或者远程web服务。但是,大多数协议都不是为了我们的应用而特殊定制的,就像我们几乎不会用HTTP协议来传输大规模文件,发送电子邮件或是进行实时通讯。我们需要的是一个高度优化的应用框架可以支持我们特殊的需求。例如,你可以搭建一个HTTP server却能同时支持优化的AJAX聊天应用,大型文件传输等等。你甚至可以设计自己的一个网络通讯协议。
解决方法:
Netty是一个高效的、异步的、基于事件驱动的网络通讯框架。使用Netty 可以快速开发出可维护的,高性能、高扩展能力的协议服务及其客户端应用。也就是说, 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
“快速”和“简单”并不意味着会让你的最终应用产生维护性或性能上的问题。Netty是一个吸收了多种协议的实现经验,这些协议包括FTP,SMPT,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
一些用户可能找到了某些同样声称具有这些特性的编程框架,因此你们可能想问Netty又有什么不一样的地方。这个问题的答案是Netty项目的设计哲学。从创立之初,无论是在API还是在其实现上Netty都致力于为你提供最为舒适的使用体验。虽然这并不是显而易见的,但你终将会认识到这种设计哲学将令你在阅读本指南和使用Netty时变得更加得轻松和容易。
客户端与服务器的搭建:
在详细介绍使用之前,先给出客户端与服务器端基本框架的搭建,以下程序以一个简单的时间服务为例,即客户端向服务器发送连接请求,服务器在收到请求之后就向客户端发送当前系统时间。在后续博客中会介绍每个环节的具体注意事项。废话就不多说了,先上:
服务器端:
TimeServer.java:
package org.jboss.netty.example.
import java.net.InetSocketA
import java.util.concurrent.E
import org.jboss.netty.bootstrap.ServerB
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelP
import org.jboss.netty.channel.ChannelPipelineF
import org.jboss.netty.channel.C
import org.jboss.netty.channel.group.ChannelG
import org.jboss.netty.channel.group.ChannelGroupF
import org.jboss.netty.channel.group.DefaultChannelG
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelF
public class TimeServer {
static final ChannelGroup allChannels = new DefaultChannelGroup("time-server" );
public static void main(String[] args) throws Exception{
ChannelFactory factory = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
public ChannelPipeline getPipeline(){
return Channels.pipeline(
new TimeServerHandler(),
new TimeEncoder()
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
Channel channel = bootstrap.bind(new InetSocketAddress(8080));
allChannels.add(channel);
waitForShutdownCommand();
ChannelGroupFuture future = allChannels.close();
future.awaitUninterruptibly();
factory.releaseExternalResources();
package org.jboss.netty.example.
import java.net.InetSocketA
import java.util.concurrent.E
import org.jboss.netty.bootstrap.ServerB
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelP
import org.jboss.netty.channel.ChannelPipelineF
import org.jboss.netty.channel.C
import org.jboss.netty.channel.group.ChannelG
import org.jboss.netty.channel.group.ChannelGroupF
import org.jboss.netty.channel.group.DefaultChannelG
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelF
public class TimeServer {
//DefaultChannelGroup requires the name of the group as a constructor parameter. The group
//name is solely used to distinguish one group from others.
static final ChannelGroup allChannels = new DefaultChannelGroup("time-server" );
public static void main(String[] args) throws Exception{
ChannelFactory factory = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
public ChannelPipeline getPipeline(){
return Channels.pipeline(
new TimeServerHandler(),
new TimeEncoder()
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
Channel channel = bootstrap.bind(new InetSocketAddress(8080));
allChannels.add(channel);
waitForShutdownCommand();
ChannelGroupFuture future = allChannels.close();
future.awaitUninterruptibly();
factory.releaseExternalResources();
TimeServerHandler.java:
package org.jboss.netty.example.
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelFutureL
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.ChannelStateE
import org.jboss.netty.channel.ExceptionE
import org.jboss.netty.channel.SimpleChannelH
public class TimeServerHandler extends SimpleChannelHandler{
private static String a = "Hello";
public TimeServerHandler(){
System.out.println("Hello world " + a);
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
UnixTime time = new UnixTime(System.currentTimeMillis() / 1000);
ChannelFuture f = e.getChannel().write(time);
f.addListener(ChannelFutureListener.CLOSE);
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
TimeServer.allChannels.add(e.getChannel());
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e){
e.getCause().printStackTrace();
Channel ch = e.getChannel();
ch.close();
package org.jboss.netty.example.
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelFutureL
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.ChannelStateE
import org.jboss.netty.channel.ExceptionE
import org.jboss.netty.channel.SimpleChannelH
public class TimeServerHandler extends SimpleChannelHandler{
// @Override
// public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){
Channel ch = e.getChannel();
ChannelBuffer time =
ChannelBuffers.buffer(4);
time.writeInt((int)(System.currentTimeMillis()/1000));
ChannelFuture f = ch.write(time);
f.addListener(new ChannelFutureListener(){
public void operationComplete(ChannelFuture future){
Channel ch = future.getChannel();
ch.close();
private static String a = "Hello";
public TimeServerHandler(){
System.out.println("Hello world " + a);
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
UnixTime time = new UnixTime(System.currentTimeMillis() / 1000);
ChannelFuture f = e.getChannel().write(time);
f.addListener(ChannelFutureListener.CLOSE);
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
TimeServer.allChannels.add(e.getChannel());
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e){
e.getCause().printStackTrace();
Channel ch = e.getChannel();
ch.close();
TimeEncoder.java:
package org.jboss.netty.example.
import static org.jboss.netty.buffer.ChannelBuffers.
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.C
import org.jboss.netty.channel.MessageE
import org.jboss.netty.channel.SimpleChannelH
public class TimeEncoder extends SimpleChannelHandler{
public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) {
UnixTime time = (UnixTime) e.getMessage();
ChannelBuffer buf = buffer(4);
buf.writeInt((int)time.getValue());
Channels.write(ctx, e.getFuture(), buf);
package org.jboss.netty.example.
import static org.jboss.netty.buffer.ChannelBuffers.
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.C
import org.jboss.netty.channel.MessageE
import org.jboss.netty.channel.SimpleChannelH
public class TimeEncoder extends SimpleChannelHandler{
public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) {
UnixTime time = (UnixTime) e.getMessage();
ChannelBuffer buf = buffer(4);
buf.writeInt((int)time.getValue());
Channels.write(ctx, e.getFuture(), buf);
客户端代码:
TimeClient.java:
package org.jboss.netty.example.
import java.net.InetSocketA
import java.util.concurrent.E
import org.jboss.netty.bootstrap.ClientB
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelP
import org.jboss.netty.channel.ChannelPipelineF
import org.jboss.netty.channel.C
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelF
public class TimeClient {
public static void main(String[] args) throws Exception{
String host = args[0];
int port = Integer.parseInt(args[1]);
ChannelFactory factory = new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ClientBootstrap bootstrap = new
ClientBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline(){
return Channels.pipeline(
new TimeDecoder(),
new TimeClientHandler());
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,port));
future.awaitUninterruptibly();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
future.getChannel().getCloseFuture().awaitUninterruptibly();
factory.releaseExternalResources();
package org.jboss.netty.example.
import java.net.InetSocketA
import java.util.concurrent.E
import org.jboss.netty.bootstrap.ClientB
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelP
import org.jboss.netty.channel.ChannelPipelineF
import org.jboss.netty.channel.C
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelF
public class TimeClient {
public static void main(String[] args) throws Exception{
String host = args[0];
int port = Integer.parseInt(args[1]);
String host = "localhost";
int port = 8080;
ChannelFactory factory = new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ClientBootstrap bootstrap = new
ClientBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline(){
return Channels.pipeline(
new TimeDecoder(),
new TimeClientHandler());
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,port));
future.awaitUninterruptibly();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
future.getChannel().getCloseFuture().awaitUninterruptibly();
factory.releaseExternalResources();
TimeDecoder.java:
package org.jboss.netty.example.
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.handler.codec.frame.FrameD
public class TimeDecoder extends FrameDecoder{
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){
if(buffer.readableBytes() & 4){
return null;
return new UnixTime(buffer.readInt());
package org.jboss.netty.example.
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.handler.codec.frame.FrameD
public class TimeDecoder extends FrameDecoder{
// @Override
// protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){
if(buffer.readableBytes() & 4){
return buffer.readBytes(4);
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){
if(buffer.readableBytes() & 4){
return new UnixTime(buffer.readInt());
TimeClientHandler.java:
package org.jboss.netty.example.
import java.util.D
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.MessageE
import org.jboss.netty.channel.SimpleChannelH
public class TimeClientHandler extends SimpleChannelHandler{
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){
UnixTime m = (UnixTime)e.getMessage();
System.out.println(m);
e.getChannel().close();
package org.jboss.netty.example.
import java.util.D
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.MessageE
import org.jboss.netty.channel.SimpleChannelH
public class TimeClientHandler extends SimpleChannelHandler{
// @Override
// public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){
ChannelBuffer buf = (ChannelBuffer)e.getMessage();
long currentTimeMillis = buf.readInt() * 1000L;
System.out.println(new Date(currentTimeMillis));
e.getChannel().close();
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){
UnixTime m = (UnixTime)e.getMessage();
System.out.println(m);
e.getChannel().close();
共用数据结构:
UnixTime.java:
package org.jboss.netty.example.
import java.util.D
public class UnixTime {
private final long
public UnixTime(long value){
this.value =
public long getValue(){
public String toString(){
return new Date(value * 1000L).toString();
package org.jboss.netty.example.
import java.util.D
public class UnixTime {
public UnixTime(long value){
this.value =
public long getValue(){
public String toString(){
return new Date(value * 1000L).toString();
&&&&推荐文章:
【上篇】【下篇】

我要回帖

更多关于 netty做游戏服务器 的文章

 

随机推荐