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

Posted

技术标签:

【中文标题】java中使用netty的SPDY客户端和服务器【英文标题】:SPDY client and server in java using netty 【发布时间】:2012-11-24 01:39:30 【问题描述】:
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 的服务器示例,我可以通过在 Internet 上的多个地方阅读,使用 netty 库将其组合在一起。当我运行此服务器并使用 SPDY 客户端连接时,我的连接成功,因为我可以在 channelOpen 和 channelConnected 函数中看到消息。

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

以上是关于java中使用netty的SPDY客户端和服务器的主要内容,如果未能解决你的问题,请参考以下文章

将 SPDY 与 Netty 一起使用

Netty 4.0 SPDY 文件传输不工作

在 Android 上添加 spdy 编解码器后使用 netty 连接失败

java是如何实现客服在线聊天功能的?

使用 java 客户端与 spdy 服务器对话

netty系列之:让TLS支持http2