当我们需要通过网页直接访问XenServer的vm console时,我们可以直接使用websocket建立和xenserver的连接,这种方式有个问题是xenserver的主机为了支持这种WebSocket的访问方式,会在Xenserver的主机上面起很多wsproxy,作为xenserver vm console和websocket的代理。若我们不希望Xenserver加大负担,我们希望实现自己的webproxy,然后访问Xenserver Vm console,下面就是这种方法的介绍。
思路很简单,两个步骤:
1、创建一个websocketproxy服务
2、基于这个服务访问Xenserver vm console
这个websocketproxy的实现基于netty(netty是一个高性能的异步事件IO框架),下面是关键代码:
收到消息时先进行判断,若是建立websocket的连接,则消息类型肯定是HttpRequest,因为websocket协议是基于Http协议的。简单来说就是将http协议进行升级,从而变为websocket协议。进而调用ensureTargetConnect函数,连接具体的VM Console。
在ensureTargetConnect函数中,我们先是建立和Xenserver的连接,当连接建立之后,再发送消息给Xenserver,这个消息采用类似HTTP格式的非标准HTTP协议,具体参见makeHeaders函数,若和具体的VM Console建立好连接,则Xenserver会返回一个HTTP 200的状态码,表示我们已经和VM Console 成功建立连接了,这时Xenserver会立马发送这个VM Console的协议版本号。
@Override
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e)
throws Exception {
Object msg = e.getMessage();
// An HttpRequest means either an initial websocket connection
// or a web server request
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg, e);
// A WebSocketFrame means a continuation of an established websocket connection
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg, e);
// A channel buffer we treat as a VNC protocol request
} else if (msg instanceof ChannelBuffer) {
handleVncDirect(ctx, (ChannelBuffer) msg, e, null);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req, final MessageEvent e) throws Exception {
// Allow only GET methods.
if (req.getMethod() != GET) {
Logger.getLogger(WebsockifyProxyHandler.class.getName()).info("Just support GET Method.");
return;
}
String upgradeHeader = req.getHeader("Upgrade");
if(upgradeHeader != null && upgradeHeader.toUpperCase().equals("WEBSOCKET")){
Logger.getLogger(WebsockifyProxyHandler.class.getName()).fine("Websocket request from " + e.getRemoteAddress() + ".");
// Handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
this.getWebSocketLocation(req), "base64", false);
this.handshaker = wsFactory.newHandshaker(req);
if (this.handshaker == null) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
} else {
// deal with a bug in the flash websocket emulation
// it specifies WebSocket-Protocol when it seems it should specify Sec-WebSocket-Protocol
String protocol = req.getHeader("WebSocket-Protocol");
String secProtocol = req.getHeader("Sec-WebSocket-Protocol");
if(protocol != null && secProtocol == null )
{
req.addHeader("Sec-WebSocket-Protocol", protocol);
}
this.handshaker.handshake(ctx.getChannel(), req);
}
ensureTargetConnection (e, true, null, req.getUri());
}
}
private void ensureTargetConnection(ChannelEvent e, boolean websocket, final Object sendMsg, String para)
throws Exception {
if(outboundChannel == null) {
String[] paras = para.split("&");
String[] uuids = paras[0].split("=");
String[] authids = paras[1].split("=");
// Suspend incoming traffic until connected to the remote host.
final Channel inboundChannel = e.getChannel();
inboundChannel.setReadable(false);
Logger.getLogger(WebsockifyProxyHandler.class.getName()).info("Inbound proxy connection from " + inboundChannel.getRemoteAddress()
+ " uuid=" + uuids[1] + " authid=" + authids[1] + ".");
// resolve the target
Console console = Websockify.ConsoleMap.get(uuids[1]);
final String location = console.getLocation(Websockify.Conn);
InetSocketAddress target = new InetSocketAddress(new URL(location).getHost(), 80);
// Start the connection attempt.
ClientBootstrap cb = new ClientBootstrap(cf);
cb.getPipeline().addLast("aggregator", new HttpChunkAggregator(65536));
if ( websocket ) {
cb.getPipeline().addLast("handler", new OutboundWebsocketHandler(e.getChannel(), trafficLock));
}
else {
cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel(), trafficLock));
}
ChannelFuture f = cb.connect(target);
outboundChannel = f.getChannel();
if ( sendMsg != null ) outboundChannel.write(sendMsg);
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// Connection attempt succeeded:
// Begin to accept incoming traffic.
connectVmConsole(location);
inboundChannel.setReadable(true);
Logger.getLogger(WebsockifyProxyHandler.class.getName()).info("Created outbound connection to " + location + ".");
} else {
Logger.getLogger(WebsockifyProxyHandler.class.getName()).severe("Failed to create outbound connection to " + location + ".");
inboundChannel.close();
}
}
});
} else {
if ( sendMsg != null ) outboundChannel.write(sendMsg);
}
}
private void connectVmConsole(String location) throws BadServerResponse, XenAPIException, XmlRpcException, MalformedURLException {
URL uri = new URL(location);
String headers[] = makeHeaders(uri.getPath().concat("?").concat(uri.getQuery()), uri.getHost(), Websockify.Conn.getSessionReference());
for (String header : headers) {
ChannelBuffer msgdata = new BigEndianHeapChannelBuffer(header.getBytes());
outboundChannel.write(msgdata);
outboundChannel.write(new BigEndianHeapChannelBuffer("\r\n".getBytes()));
}
}
private String[] makeHeaders(String path, String host, String session) {
String[] headers = { String.format("CONNECT %s HTTP/1.1", path),
String.format("Host: %s", host),
String.format("Cookie: session_id=%s", session), "" };
return headers;
}
参考资料:
http://docs.vmd.citrix.com/XenServer/5.6.0fp1/1.0/en_gb/sdk.html#retrieving_vnc_consoles_with_api
http://blogs.citrix.com/2011/02/11/xenserverconsole-examples/
转自:http://blog.csdn.net/pingnanlee/article/details/13627573
分享到:
相关推荐
JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA...
使用netty作为proxy的例子。 maven。 直接运行
基于Netty实现的命令行斗地主游戏,为划水摸鱼而生~ 基于Netty实现的命令行斗地主游戏,为划水摸鱼而生~ 基于Netty实现的命令行斗地主游戏,为划水摸鱼而生~ 基于Netty实现的命令行斗地主游戏,为划水摸鱼而生...
1、基于netty+websocket+springboot的实时聊天系统项目源码.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料...
基于netty框架编写的socket服务器
一个基于netty实现web框架,或者mvc框架,实现基于netty的web框架,你说netty强不强,文中有不对的地方,欢迎大牛指正
基于Netty框架开发的Modbus源代码。支持 * READ COILS | 0x01 * READ DISCRETE INPUTS | 0x02 * READ HOLDING REGISTERS | 0x03 * READ INPUT REGISTERS | 0x04 * WRITE SINGLE COIL | 0x05 * WRITE SINGLE REGISTER...
基于Netty实现了dubbo rpc
毕设项目:基于netty+websocket+springboot的实时聊天系统 毕设项目:基于netty+websocket+springboot的实时聊天系统 毕设项目:基于netty+websocket+springboot的实时聊天系统 毕设项目:基于netty+websocket+...
基于Netty实现的内网穿透&反向代理的工具 (支持TCP上层协议和HTTP的穿透式反向代理).zip
基于netty的安全即时通讯系统源码+项目说明.zip基于netty的安全即时通讯系统源码+项目说明.zip基于netty的安全即时通讯系统源码+项目说明.zip基于netty的安全即时通讯系统源码+项目说明.zip基于netty的安全即时通讯...
使用Netty进行网络通信,完成分布式的数据采集任务,可以采集500以上数据节点。
基于Netty手写Dubbo,该资源包含 1、生产者向zk服务的注册,消费者发现服务。 2、RPC远程调用实现。 3、netty服务调用,对象序列化和反序列化。 4、负载均衡的简单实现 详情见博客:...
基于 Netty 开发的 Java 游戏服务端框架,目前提供 CocosCreator 和 Unity 的客户端SDK.zip 基于 Netty 开发的 Java 游戏服务端框架,目前提供 CocosCreator 和 Unity 的客户端SDK.zip 基于 Netty 开发的 Java 游戏...
基于netty开发的android端即时通讯,代码能够运行,并有代码注释
从最简单的Socked编程,到目前为止已经有了开源的框架,那就是Netty,它Jobss开发的一个网络异步应用框架,能高快捷的实现网络客户端和服务器端的优秀框架,而本实例就是基于这个框架实现的聊天程序,希望对你有用
基于netty 的udp字节数据接 收服务,发送服务实例 基于netty 的udp字节数据接收服务,发送服务实例
基于Netty的RPC架构实战演练 让你深入java的服务器开发
一个基于netty封装的快速分布式任务开发框架,目标:简单,简单,再简单! easynetty-demo是用spring-boot,spring-shell实现的示例