使用netty的java中的SPDY客户端和服务器

时间:2012-12-06 03:45:25

标签: java webserver netty spdy

Server

import java.util.concurrent.atomic.AtomicReference;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.spdy.DefaultSpdySynStreamFrame;

public class SpdyChannelUpStreamHandler extends SimpleChannelUpstreamHandler {
volatile Channel channel;
final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();

@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
        throws Exception {
    System.out.println("Channel In Open Stage");
    channel = e.getChannel();

}

@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
        throws Exception {
    System.out.println("Channel In Connected Stage");
    Channels.write(channel, new DefaultSpdySynStreamFrame(1, 1, (byte)0));
}

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
        throws Exception {
    System.out.println("Message Received on Server Side");
     Channels.write(channel, e.getMessage(), e.getRemoteAddress());
}


@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
        throws Exception {
     if (exception.compareAndSet(null, e.getCause())) {
         e.getChannel().close();
     }
}

}

import static org.jboss.netty.channel.Channels.pipeline;

import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.spdy.SpdyFrameDecoder;
import org.jboss.netty.handler.codec.spdy.SpdyFrameEncoder;
import org.jboss.netty.handler.codec.spdy.SpdySessionHandler;

public class SpdyPipeLineFactory implements ChannelPipelineFactory{

@Override
public ChannelPipeline getPipeline() throws Exception {
    ChannelPipeline pipeline = pipeline();
    pipeline.addLast("decoder", new SpdyFrameDecoder(2));
    pipeline.addLast("encoder", new SpdyFrameEncoder(2));
    //pipeline.addLast("sessionHandler",new SpdySessionHandler(2,true));
    pipeline.addLast("handler", new SpdyChannelUpStreamHandler());
    return pipeline;
}

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

public class StartServer {
public static void main(String[] args){
ServerBootstrap bootStrapServer = new ServerBootstrap(new 
        NioServerSocketChannelFactory(Executors.newCachedThreadPool(), 
        Executors.newCachedThreadPool()));
    bootStrapServer.setPipelineFactory(new SpdyPipeLineFactory());
    bootStrapServer.bind(new InetSocketAddress(8443));
}


}

这是支持SPDY的服务器示例,我可以通过在互联网上的多个位置阅读来使用netty库将它们组合在一起。当我运行此服务器并使用SPDY客户端连接时,我的连接成功,因为我可以看到channelOpen和channelConnected函数中的消息。

我想问几个问题,因为我对SPDY协议的理解非常有限。我将从我想要做的第一件事开始。

1 - 服务器如何将消息发送到客户端,目前我在channelConnected方法中执行此操作,我可以在客户端看到,但这使我在通道设置期间发送消息和channelConnected事件的机会非常有限过程,

有没有办法获取SPDY服务器上当前所有开放频道的句柄并识别这些频道,以便我可以按需选择频道并使用它们发送消息?

1 个答案:

答案 0 :(得分:0)

最好的办法是创建一个共享的ChannelGroup,每当新频道连接时,将频道添加到ChannelGroup。您需要根据可用的通道元数据(例如远程地址或通道ID)确定如何识别要发送到的通道。然后,您可以从ChannelGroup检索通道并将消息写入其中。 ChannelGroup的其他优点是

  • 当频道关闭时,它们会自动从频道组中删除。
  • 您可以在ChannelGroup上调用close来关闭所有包含的频道。
  • 您可以调用ChannelGroup上的写入来向所有包含的通道写入消息。

我编写了一个扩展的通道包装器,因此我可以将其他元数据与通道相关联。我的协议的一部分是,当一个新的频道连接时,我发送一个WHO消息,客户端响应一些客户端身份值,我添加到频道包装器。我还实现了一个JMX接口,该接口公开了组中的通道,因此我可以准确地看到客户端连接的内容。

Screen shot of enhanced channel meta-data in JConsole