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

虚拟机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。

@Override
	protected void doRead(HttpServletRequest request, HttpServletResponse response, String tunnelUUID)
			throws GuacamoleException {

		// Get tunnel, ensure tunnel exists
		GuacamoleTunnel tunnel = getTunnel(tunnelUUID);

		// Ensure tunnel is open
		if (!tunnel.isOpen())
			throw new GuacamoleResourceNotFoundException("Tunnel is closed.");

		// Obtain exclusive read access
		GuacamoleReader 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 response
			Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), "UTF-8"));

			// Stream data to response, ensuring output stream is closed
			try {

				// Deregister tunnel and throw error if we reach EOF without
				// having ever sent any data
				char[] message = reader.read();
				if (message == null)
					throw new GuacamoleConnectionClosedException("Tunnel reached end of stream.");
				// 这里是我添加的代码--begin
				// guacd server error
				if (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 bytes
					out.write(message, 0, message.length);

					// Flush if we expect to wait
					if (!reader.available()) {
						out.flush();
						response.flushBuffer();
					}

					// No more messages another stream can take over
					if (tunnel.hasQueuedReaderThreads())
						break;

				} while (tunnel.isOpen() && (message = reader.read()) != null);

				// Close tunnel immediately upon EOF
				if (message == null) {
					deregisterTunnel(tunnel);
					tunnel.close();
				}

				// End-of-instructions marker
				out.write("0.;");
				out.flush();
				response.flushBuffer();
			}

			// Send end-of-stream marker and close tunnel if connection is
			// closed
			catch (GuacamoleConnectionClosedException e) {
				// Deregister and close
				deregisterTunnel(tunnel);
				tunnel.close();

				// End-of-instructions marker
				out.write("0.;");
				out.flush();
				response.flushBuffer();

			}

			catch (GuacamoleException e) {

				// Deregister and close
				deregisterTunnel(tunnel);
				tunnel.close();
				throw e;
			}

			// Always close output stream
			finally {
				out.close();
			}

		} catch (IOException e) {

			// Log typically frequent I/O error if desired
			log.debug("Error writing to servlet output stream", e);

			// Deregister and close
			deregisterTunnel(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 providerId
				tunnel = new GuacamoleVncReconnectTunnel(
						new ConfiguredGuacamoleSocket(getSocket(""), configuration), tunnelUUID);
				registerTunnel(tunnel);
				doRead(request, response, tunnelUUID);
			}
		}
	}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值