基于netty4.0+spring的游戏完整架构 博客分类: java 游戏
程序员文章站
2024-03-06 19:19:32
...
之前写过一篇和本文类似的博客,不过原博客是基于netty3.x实现的,今天整理了一份基于4.0的完整系统分享给大家,希望能对大家有所帮助。
架构细节原博客都有,请参照 http://cpjsjxy.iteye.com/blog/1587601
propholder.xml
settings.properties
测试类
TestClient
ClientInboundHandler
本测试代码已经过http、socket、websocket测试。
鉴于很多朋友想深入交流,特提供源码demo项目下载地址:
https://github.com/pofuchenzhou/netty-spring-game.git
架构细节原博客都有,请参照 http://cpjsjxy.iteye.com/blog/1587601
propholder.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>config/properties/settings.properties</value> </list> </property> </bean> <bean id="serverInitializer" class="com.cp.netty.ServerInitializer" init-method="init"> <property name="timeout" value="${app.channel.readtimeout}" /> <property name="handlerDispatcher" ref="handlerDispatcher" /> <property name="requestType" value="${app.requestType}" /> </bean> <bean id="handlerDispatcher" class="com.cp.dispatcher.HandlerDispatcher"> <property name="messageExecutor"> <bean class="com.cp.domain.FiexThreadPoolExecutor" destroy-method="shutdown"> <constructor-arg value="${app.handler.pool.corePoolSize}" /> <constructor-arg value="${app.handler.pool.maximumPoolSize}" /> <constructor-arg value="${app.handler.pool.keepAliveSecond}" /> <constructor-arg value="${app.handler.pool.name}" /> </bean> </property> <property name="sleepTime" value="${app.handler.sleepTime}" /> <property name="handlerMap" ref="gameHandlerMap" /> </bean> <bean id="gameHandlerMap" class="java.util.HashMap"> <constructor-arg> <map> <entry key="999"> <bean class="com.cp.handler.InitHandler"> </bean> </entry> </map> </constructor-arg> </bean> </beans>
settings.properties
app.handler.pool.corePoolSize=16 app.handler.pool.maximumPoolSize=32 app.handler.pool.keepAliveSecond=300 app.handler.pool.name=gamework app.handler.sleepTime=10 app.channel.readtimeout = 3600 #http socket websocket_text websocket_binary app.requestType=socket
测试类
TestClient
package com.cp.test; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.codec.http.HttpVersion; import java.net.URI; import com.cp.domain.ERequestType; public class TestClient { public void connect(String host, int port, final ERequestType requestType) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); String msg = "Are you ok?"; if (ERequestType.SOCKET.equals(requestType)) { try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class).option( ChannelOption.TCP_NODELAY, true); b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000); b.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( "encode", new LengthFieldBasedFrameDecoder( Integer.MAX_VALUE, 0, 4, 0, 4)); ch.pipeline().addLast("decode", new LengthFieldPrepender(4)); ch.pipeline().addLast("handler", new ClientInboundHandler()); } }); ChannelFuture f = b.connect(host, port).sync(); ByteBuf messageData = Unpooled.buffer(); messageData.writeInt(999); messageData.writeInt(msg.length()); messageData.writeBytes(msg.getBytes()); f.channel().writeAndFlush(messageData).sync(); f.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } } else if (ERequestType.HTTP.equals(requestType)) { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { // 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码 ch.pipeline().addLast(new HttpResponseDecoder()); // 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码 ch.pipeline().addLast(new HttpRequestEncoder()); ch.pipeline().addLast(new ClientInboundHandler()); } }); ChannelFuture f = b.connect(host, port).sync(); b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true); b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000); URI uri = new URI("http://" + host + ":" + port); DefaultFullHttpRequest request = new DefaultFullHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, uri.toASCIIString(), Unpooled.wrappedBuffer(msg.getBytes("UTF-8"))); // 构建http请求 request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes()); // 发送http请求 f.channel().write(request); f.channel().flush(); f.channel().closeFuture().sync(); } try { } finally { workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { TestClient client = new TestClient(); client.connect("127.0.0.1", 8080, ERequestType.SOCKET); } }
ClientInboundHandler
package com.cp.test; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; public class ClientInboundHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; System.out.println("CONTENT_TYPE:" + response.headers().get(HttpHeaders.Names.CONTENT_TYPE)); } if (msg instanceof HttpContent) { HttpContent content = (HttpContent) msg; ByteBuf buf = content.content(); System.out.println(buf.toString(io.netty.util.CharsetUtil.UTF_8)); buf.release(); } if (msg instanceof ByteBuf) { ByteBuf messageData = (ByteBuf) msg; int commandId = messageData.readInt(); int length = messageData.readInt(); byte[] c = new byte[length]; messageData.readBytes(c); System.out.println("commandId:"+commandId+"\tmessage:"+new String(c)); } } }
本测试代码已经过http、socket、websocket测试。
鉴于很多朋友想深入交流,特提供源码demo项目下载地址:
https://github.com/pofuchenzhou/netty-spring-game.git
推荐阅读
-
基于netty4.0+spring的游戏完整架构 博客分类: java 游戏
-
基于netty4.0+spring的游戏完整架构 博客分类: java 游戏
-
java游戏架构那点事儿(二) 博客分类: java 游戏 游戏框架netty
-
java游戏架构那点事儿(三) 博客分类: java 游戏 java游戏架构多线程ThreadPoolExecutor
-
java游戏架构那点事儿(一) 博客分类: java 游戏 游戏框架
-
手游更需要基于熟人的强碎片化社交系统 博客分类: java 游戏需求分析 游戏网游社交
-
一个高难度的 Java 3D 智力游戏,立方四子棋 博客分类: Java 游戏Java.netHTML
-
一个高难度的 Java 3D 智力游戏,立方四子棋 博客分类: Java 游戏Java.netHTML
-
Oracle正式收购Sun后对JDK的态度 博客分类: IT SUNOracleJDK游戏Java
-
Oracle正式收购Sun后对JDK的态度 博客分类: IT SUNOracleJDK游戏Java