tomcat+netty实现TCP连接服务

netty是一个异步的、事件驱动的网络应用程序框架,通过netty可以简化TCP和UDP的socket服务开发(注:目前BAE不支持UDP协议)。

BAE提供的是标准的servlet container环境(tomcat和jetty,本文主要以tomcat为例子),那如何在这样的环境下初始化netty并实现TCP连接的服务呢?

在servlet container环境中,可以通过实现ServletContextListener接口来监听应用启动和停止的事件,我们只需要在启动事件的处理方法中初始化netty即可。

让我们来看一个具体的例子,该例子改编自netty官方的Echo Server例子。

首先,我们需要实现一个ServletContextListener,在contextInitialized方法中初始化netty,让netty监听9000端口:

package test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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.NioServerSocketChannel;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class StartNettyServer implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) {
                                ctx.writeAndFlush(msg);
                            }
                        });
                    }
                })
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        // Bind and start to accept incoming connections.
        b.bind(9000).syncUninterruptibly();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }

}

然后,在web.xml中配置该listener:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <listener>
        <listener-class>test.StartNettyServer</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

最后,打成war包并上传部署,同时将9000端口映射到公网使其可以访问,以BAE专业版为例(BAE基础版需要使用Port服务):

点击保存修改之后,我们通过telnet连上公网IP+9000端口,就可以访问这个Echo Server,输入任何字符串并回车后,服务器会返回相同的内容:

此条目发表在 BAE使用 分类目录。将固定链接加入收藏夹。

发表评论