当前位置:首页 > 开发 > 系统架构 > 架构 > 正文

基于netty4.0+spring的游戏完整架构

发表于: 2014-11-13   作者:cpjsjxy   来源:转载   浏览:
摘要: 之前写过一篇和本文类似的博客,不过原博客是基于netty3.x实现的,今天整理了一份基于4.0的完整系统分享给大家,希望能对大家有所帮助。 架构细节原博客都有,请参照 http://cpjsjxy.iteye.com/blog/1587601 propholder.xml <?xml version="1.0" encoding="UTF
之前写过一篇和本文类似的博客,不过原博客是基于netty3.x实现的,今天整理了一份基于4.0的完整系统分享给大家,希望能对大家有所帮助。

架构细节原博客都有,请参照 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测试。

基于netty4.0+spring的游戏完整架构

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号