虚拟机vnc端口切换时如何让guacamole切换端口重试连接

来源:互联网 发布:美工培训班学费多少钱 编辑:程序博客网 时间:2024/06/16 02:57

虚拟机vnc默认端口是5901,如果虚拟机不属于正常关闭,文件/tmp/.X11-unix/X1不会被删除,当虚拟机启动的时候不会使用5901端口启动vnc server服务,而是启用5902端口(如果文件/tmp/.X11-unix/X2也存在则使用5903端口,依次类推)。


建立到guacamole代理服务器的tunnel时候需要带上vnc的连接信息,如果guacd连接目标虚拟机出错时不会抛出Exception,所以我们的代码没有办法捕获异常去换端口重试连接。

解决方案是重载GuacamoleHTTPTunnelServlet的doRead方法,通过读取webserver发出connect请求之后的第一个流数据,分析里面是否包含错误信息,如果有则重新创建一个tunnel(要拿到旧tunnel的uuid,所有的tunnel都放到map里面缓存的,key就是uuid),然后注册新的tunnel。

@Overrideprotected void doRead(HttpServletRequest request, HttpServletResponse response, String tunnelUUID)throws GuacamoleException {// Get tunnel, ensure tunnel existsGuacamoleTunnel tunnel = getTunnel(tunnelUUID);// Ensure tunnel is openif (!tunnel.isOpen())throw new GuacamoleResourceNotFoundException("Tunnel is closed.");// Obtain exclusive read accessGuacamoleReader reader = tunnel.acquireReader();try {// Note that although we are sending text, Webkit browsers will// buffer 1024 bytes before starting a normal stream if we use// anything but application/octet-stream.response.setContentType("application/octet-stream");response.setHeader("Cache-Control", "no-cache");// Get writer for responseWriter out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), "UTF-8"));// Stream data to response, ensuring output stream is closedtry {// Deregister tunnel and throw error if we reach EOF without// having ever sent any datachar[] message = reader.read();if (message == null)throw new GuacamoleConnectionClosedException("Tunnel reached end of stream.");// 这里是我添加的代码--begin// guacd server errorif (new String(message).contains("3.519")) {rebuildTunnel(request, response, tunnelUUID, tunnel);}// 这里是我添加的代码--end// For all messages, until another stream is ready (we send at// least one message)do {// Get message output bytesout.write(message, 0, message.length);// Flush if we expect to waitif (!reader.available()) {out.flush();response.flushBuffer();}// No more messages another stream can take overif (tunnel.hasQueuedReaderThreads())break;} while (tunnel.isOpen() && (message = reader.read()) != null);// Close tunnel immediately upon EOFif (message == null) {deregisterTunnel(tunnel);tunnel.close();}// End-of-instructions markerout.write("0.;");out.flush();response.flushBuffer();}// Send end-of-stream marker and close tunnel if connection is// closedcatch (GuacamoleConnectionClosedException e) {// Deregister and closederegisterTunnel(tunnel);tunnel.close();// End-of-instructions markerout.write("0.;");out.flush();response.flushBuffer();}catch (GuacamoleException e) {// Deregister and closederegisterTunnel(tunnel);tunnel.close();throw e;}// Always close output streamfinally {out.close();}} catch (IOException e) {// Log typically frequent I/O error if desiredlog.debug("Error writing to servlet output stream", e);// Deregister and closederegisterTunnel(tunnel);tunnel.close();} finally {tunnel.releaseReader();}}

private void rebuildTunnel(HttpServletRequest request, HttpServletResponse response, String tunnelUUID,GuacamoleTunnel tunnel) throws GuacamoleException {GuacamoleSocket socket = tunnel.getSocket();GuacamoleConfiguration configuration = ((ConfiguredGuacamoleSocket) socket).getConfiguration();if ("vnc".equalsIgnoreCase(configuration.getProtocol())) {int port = Integer.parseInt(configuration.getParameter("port"));log.warn(String.format("vnc service with [%s:%d] not work, increasing port and retry",configuration.getParameter("hostname"), port));if (port++ < 5910) {configuration.setParameter("port", port + "");deregisterTunnel(tunnel);tunnel.close();// TODO get cloud providerIdtunnel = new GuacamoleVncReconnectTunnel(new ConfiguredGuacamoleSocket(getSocket(""), configuration), tunnelUUID);registerTunnel(tunnel);doRead(request, response, tunnelUUID);}}}


原创粉丝点击