之前写过一篇和本文类似的博客,不过原博客是基于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
评论
13 楼
cpjsjxy 2016-05-17
185248148 写道
没原码啊,,,
https://github.com/pofuchenzhou/netty-spring-game
12 楼
185248148 2016-05-05
没原码啊,,,
11 楼
cpjsjxy 2016-01-21
roway 写道
weiluo12@126.com求源码,谢谢!!!
https://github.com/pofuchenzhou/netty-spring-game
10 楼
roway 2016-01-21
weiluo12@126.com求源码,谢谢!!!
9 楼
zcqshine 2015-09-06
OK 了, 基于 netty5.0的 socket 请求方式调通过了. 谢谢博主
8 楼
zcqshine 2015-09-02
请教下博主. 反编译了你的 jar 包后, 在有 switch 的地方反编译出来的语句很奇怪, 能提供下 command 类的源码吗, 还有 ERequest 这个枚举类里的请求类型的顺序是否为SOCKET("socket"), HTTP("http"), WEBSOCKET_TEXT("websocket_text"), WEBSOCKET_BINARY("websocket_binary")
如果是按照这个顺序来的话, 那么根据反编译出来的 command 类里的 switch 语句里的逻辑好像有问题.
如果是按照这个顺序来的话, 那么根据反编译出来的 command 类里的 switch 语句里的逻辑好像有问题.
7 楼
zcqshine 2015-09-02
TestClient 类84行的代码要修改, 要删掉".channel(NioSocketChannel.class)"这部分, 因为在69行处已经设置过channelFactory了, 否则运行的时候会报错:java.lang.IllegalStateException: channelFactory set already.
对了, 我用的是 netty5.0
对了, 我用的是 netty5.0
6 楼
kenjianyin 2015-04-27
楼主,求源码~谢谢
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
5 楼
ketzi 2015-01-28
socket,websocket可以使用同一个端口不?
4 楼
cpjsjxy 2014-11-26
web_dig 写道
2593399875@qq.com 谢谢
反编译自己看吧
3 楼
web_dig 2014-11-21
2593399875@qq.com 谢谢
2 楼
web_dig 2014-11-21
楼主,求源码。
1 楼
yexiaoxiao1991 2014-11-13
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e939cd30b403819757591e2ddb614f5f.gif)
相关资源推荐