`

VNC之代理

阅读更多
[size=large]  背景:使用VNC客户端去连接DC上的VNC Server,采用的是代理的方式去访问。
 
  基础研究: 使用Java实现代理服务器
 
  参考资料:
http://www.ibm.com/developerworks/cn/java/l-javaproxy/index.html
http://ethen.iteye.com/blog/783338

  参考代码:
package com.xxx.proxyserver;

import java.io.*;
import java.net.*;

public class MyHttpProxy extends Thread {
	static public int CONNECT_RETRIES = 5; // 尝试与目标主机连接次数
	static public int CONNECT_PAUSE = 5; // 每次建立连接的间隔时间
	static public int TIMEOUT = 50; // 每次尝试连接的最大时间
	static public int BUFSIZ = 1024; // 缓冲区最大字节数
	static public boolean logging = false; // 是否记录日志
	static public OutputStream log_S = null; // 日志输出流
	static public OutputStream log_C = null; // 日志输出流
	static public String LOGFILENAME_S = "log_S.txt";
	static public String LOGFILENAME_C = "log_C.txt";
	// 与客户端相连的Socket
	protected Socket csocket;

	public MyHttpProxy(Socket cs) {
		csocket = cs;
		start();
	}

	public void writeLog(int c, boolean browser) throws IOException {
		if (browser)
			log_C.write((char) c);
		else
			log_S.write((char) c);
	}

	public void writeLog(byte[] bytes, int offset, int len, boolean browser)
			throws IOException {
		for (int i = 0; i < len; i++)
			writeLog((int) bytes[offset + i], browser);
	}

	public void run() {
		String buffer = ""; // 读取请求头
		String URL = "http://www.baidu.com"; // 读取请求URL
		String host = ""; // 读取目标主机host
		int port = 80; // 默认端口80
		Socket ssocket = null;
		// cis为客户端输入流,sis为目标主机输入流
		InputStream cis = null, sis = null;
		// cos为客户端输出流,sos为目标主机输出流
		OutputStream cos = null, sos = null;
		try {
			csocket.setSoTimeout(TIMEOUT);
			cis = csocket.getInputStream();
			cos = csocket.getOutputStream();
			while (true) {
				int c = cis.read();
				if (c == -1)
					break; // -1为结尾标志
				if (c == '\r' || c == '\n')
					break;// 读入第一行数据
				buffer = buffer + (char) c;
				if (logging)
					writeLog(c, true);
			}
			// 抽取URL(<A href="http://www.baidu.com/">http://www.baidu.com/</A>)
			URL = getRequestURL(buffer);

			int n;
			// 抽取host
			n = URL.indexOf("//");
			if (n != -1)
				host = URL.substring(n + 2); // www.baidu.com/
			n = host.indexOf('/');
			if (n != -1)
				host = host.substring(0, n);// www.baidu.com

			// 分析可能存在的端口号
			n = host.indexOf(':');
			if (n != -1) {
				port = Integer.parseInt(host.substring(n + 1));
				host = host.substring(0, n);
			}
			int retry = CONNECT_RETRIES;
			while (retry-- != 0) {
				try {
					ssocket = new Socket(host, port); // 尝试建立与目标主机的连接
					break;
				} catch (Exception e) {
				}
				// 等待
				Thread.sleep(CONNECT_PAUSE);
			}
			if (ssocket != null) {
				ssocket.setSoTimeout(TIMEOUT);
				sis = ssocket.getInputStream();
				sos = ssocket.getOutputStream();
				sos.write(buffer.getBytes()); // 将请求头写入
				pipe(cis, sis, sos, cos); // 建立通信管道
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				csocket.close();
				cis.close();
				cos.close();
			} catch (Exception e1) {
				System.out.println("\nClient Socket Closed Exception:");
				e1.printStackTrace();
			}
			try {
				ssocket.close();
				sis.close();
				sos.close();
			} catch (Exception e2) {
				System.out.println("\nServer Socket Closed Exception:");
				e2.printStackTrace();
			}
		}
	}

	public String getRequestURL(String buffer) {
		String[] tokens = buffer.split(" ");
		String URL = "";
		for (int index = 0; index < tokens.length; index++) {
			if (tokens[index].startsWith("http://")) {
				URL = tokens[index];
				break;
			}
		}
		return URL;
	}
/**
*供客户端和目标服务器通过两个Socket通信
*/
	public void pipe(InputStream cis, InputStream sis, OutputStream sos,
			OutputStream cos) {
		try {
			int length;
			byte bytes[] = new byte[BUFSIZ];
			while (true) {
				try {
					if ((length = cis.read(bytes)) > 0) {
						sos.write(bytes, 0, length);
						if (logging)
							writeLog(bytes, 0, length, true);
					} else if (length < 0)
						break;
				} catch (SocketTimeoutException e) {
				} catch (InterruptedIOException e) {
					System.out.println("\nRequest Exception:");
					e.printStackTrace();
				}
				try {
					if ((length = sis.read(bytes)) > 0) {
						cos.write(bytes, 0, length);
						if (logging)
							writeLog(bytes, 0, length, false);
					} else if (length < 0)
						break;
				} catch (SocketTimeoutException e) {
				} catch (InterruptedIOException e) {
					System.out.println("\nResponse Exception:");
					e.printStackTrace();
				}
			}
		} catch (Exception e0) {
			System.out.println("Pipe异常: " + e0);
		}
	}

	public static void startProxy(int port, Class clobj) {
		try {
			ServerSocket ssock = new ServerSocket(port);
			while (true) {
				Class[] sarg = new Class[1];
				Object[] arg = new Object[1];
				sarg[0] = Socket.class;
				try {
					java.lang.reflect.Constructor cons = clobj
							.getDeclaredConstructor(sarg);
					arg[0] = ssock.accept();
					cons.newInstance(arg); // 创建HttpProxy或其派生类的实例
				} catch (Exception e) {
					Socket esock = (Socket) arg[0];
					try {
						esock.close();
					} catch (Exception ec) {
					}
				}
			}
		} catch (IOException e) {
			System.out.println("\nStartProxy Exception:");
			e.printStackTrace();
		}
	}

	// 测试用的简单main方法
	static public void main(String args[]) throws FileNotFoundException {
		System.out.println("在端口808启动代理服务器\n");
		OutputStream file_S = new FileOutputStream(new File(LOGFILENAME_S));
		OutputStream file_C = new FileOutputStream(new File(LOGFILENAME_C));
		MyHttpProxy.log_S = file_S;
		MyHttpProxy.log_C = file_C;
		MyHttpProxy.logging = true;
		MyHttpProxy.startProxy(808, MyHttpProxy.class);
	}
}


————————————VNC代理实现版——————————————————
   VNC协议分析参考资料:
http://blog.csdn.net/forever_feng/archive/2009/10/20/4703088.aspx 
       public Map<String, PipeInfo> getPipeInfos(String datacenterId) {
        Map<String, PipeInfo> result = new HashMap<String, PipeInfo>();
        PipeInfo consolePipeInfo = getConsolePipeInfo();
        PipeInfo datacenterPipeInfo = getDatacenterPipeInfo(datacenterId);
        result.put(PipeInfo.CONSOLE_PIPE_INFO_KEY, consolePipeInfo);
        result.put(PipeInfo.DATACENTER_PIPE_INFO_KEY, datacenterPipeInfo);
        return result;
    }

         private PipeInfo getConsolePipeInfo() {
        PipeInfo pipeInfo = new PipeInfo();
        pipeInfo.setPipeIp(SystemConfigUtil.getCloudOuterIp());
        pipeInfo.setPipePort(pipeService.getPort());
        return pipeInfo;
    }

public class PipeInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    public static String CONSOLE_PIPE_INFO_KEY = "CONSOLE_PIPE_INFO_KEY";
    public static String DATACENTER_PIPE_INFO_KEY = "DATACENTER_PIPE_INFO_KEY";
    private String pipeIp;
    private int pipePort;
    
    public String getPipeIp() {
        return pipeIp;
    }
    public void setPipeIp(String pipeIp) {
        this.pipeIp = pipeIp;
    }
    public int getPipePort() {
        return pipePort;
    }
    public void setPipePort(int pipePort) {
        this.pipePort = pipePort;
    }

   public class PipeService implements InitializingBean, DisposableBean, Runnable{
    private int port;
    
    public PipeService(){
    }
    
    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    private PipeServer server;

    @Override
    public void afterPropertiesSet() throws Exception {
        new Thread(this).start();
    }

    @Override
    public void destroy() throws Exception {
        if(server != null) {
            server.stop();
        }
    }

    @Override
    public void run() {
        try {
            server = new PipeServer();
            InetAddress localAddress = InetAddress.getByName("0.0.0.0");
            server.start(port, 5, localAddress);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

  public class PipeServer implements Runnable {
	static final int START_MODE = 0;
	static final int ACCEPT_MODE = 1;
	static final int PIPE_MODE = 2;
	static final int ABORT_MODE = 3;

	static final int BUF_SIZE = 8192;

	Socket sock = null, remote_sock = null;
	ServerSocket ss = null;
	InputStream in, remote_in;
	OutputStream out, remote_out;
	PipeMessage msg;

	int mode;
	Thread pipe_thread1, pipe_thread2;
	long lastReadTime;

	static int iddleTimeout = 180000; // 3 minutes
	static PrintStream log = System.out;

	PipeServer() {
	}

	public PipeServer(Socket s) {
		this.sock = s;
		mode = START_MODE;
	}

	public void start(int port, int backlog, InetAddress localIP) {
		try {
			ss = new ServerSocket(port, backlog, localIP);
			log("Starting Pipe Server on:" + ss.getInetAddress().getHostAddress() + ":" + ss.getLocalPort());
			while (true) {
				Socket s = ss.accept();
				log("Accepted from:" + s.getInetAddress().getHostName() + ":" + s.getPort());
				PipeServer ps = new PipeServer(s);
				(new Thread(ps)).start();
			}
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
		}
	}

	static final void log(String s) {
		if (log != null) {
			log.println(s);
			log.flush();
		}
	}

	public static void setLog(OutputStream out) {
		if (out == null) {
			log = System.out;
		} else {
			log = new PrintStream(out, true);
		}
	}

	@Override
	public void run() {
		switch (mode) {
		case START_MODE:
			try {
				startSession();
			} catch (IOException ioe) {
				// handleException(ioe);
				ioe.printStackTrace();
			} finally {
				abort();
				log("Client to remote,  stopped.");
			}
			break;
		case PIPE_MODE:
			try {
				pipe(remote_in, out);
			} catch (IOException ioe) {
			} finally {
				abort();
				log("Remote to client, stopped");
			}
			break;
		case ABORT_MODE:
			break;
		default:
			log("Unexpected MODE " + mode);
		}
	}

	private void pipe(InputStream in, OutputStream out) throws IOException {
		lastReadTime = System.currentTimeMillis();
		byte[] buf = new byte[BUF_SIZE];
		int len = 0;
		while (len >= 0) {
			try {
				if (len != 0) {
					out.write(buf, 0, len);
					out.flush();
				}
				len = in.read(buf);
				lastReadTime = System.currentTimeMillis();
			} catch (InterruptedIOException iioe) {
				if (iddleTimeout == 0)
					break;// Other thread interrupted us.
				long timeSinceRead = System.currentTimeMillis() - lastReadTime;
				if (timeSinceRead >= iddleTimeout - 1000) // -1s for adjustment.
					break;
				len = 0;

			}
		}
	}

	private synchronized void abort() {
		if (mode == ABORT_MODE)
			return;
		mode = ABORT_MODE;
		try {
			log("Aborting operation");
			if (pipe_thread1 != null) {
                pipe_thread1.interrupt();
            }
            if (pipe_thread2 != null) {
                pipe_thread2.interrupt();
            }
            if (sock.isBound() && !sock.isClosed()) {
                sock.close();
            }
            if (remote_sock.isBound() && !remote_sock.isClosed()) {
				remote_sock.close();
			}
//			if (ss != null) {
//				ss.close();
//			}
			
		} catch (IOException ioe) {
		}
	}

	private void startSession() throws IOException {
		sock.setSoTimeout(iddleTimeout);

		in = sock.getInputStream();
		out = sock.getOutputStream();
		msg = readMsg(in);
		handleRequest(msg);
	}

	private PipeMessage readMsg(InputStream in) throws IOException {
		PipeMessage msg;

		msg = new PipeMessage(in);
		return msg;
	}

	private void handleRequest(PipeMessage msg) throws IOException {
		log(msg.toString());

		switch (msg.command) {
		case PipeMessage.PIPE_CMD_CONNECT:
			onConnect(msg);
			break;
		default:
			throw new PipeException(PipeMessage.PIPE_CMD_NOT_SUPPORTED, "Pipe command does not support");
		}
	}

	private void onConnect(PipeMessage msg) throws IOException {
		Socket s = null;

		try {
			if (msg.ipsSize == 1) {
				s = new Socket(msg.ips[0], msg.ports[0]);
			} else {
				PipeMessage pm = new PipeMessage(PipeMessage.PIPE_CMD_CONNECT, msg.ips, msg.ports, 1);
				s = new Socket(msg.ips[0], msg.ports[0]);
				pm.write(s.getOutputStream());
			}

			log("Connected to " + s.getInetAddress() + ":" + s.getPort());
		} catch (Exception sE) {
			log("Failed connecting to remote socket. Exception: " + sE.getLocalizedMessage());
		}

		if (s != null) {
			startPipe(s);
		} else {
			throw (new RuntimeException("onConnect() Failed to create Socket()"));
		}

		return;
	}

	private void startPipe(Socket s) {
		mode = PIPE_MODE;
		remote_sock = s;
		try {
			remote_in = s.getInputStream();
			remote_out = s.getOutputStream();
			pipe_thread1 = Thread.currentThread();
			pipe_thread2 = new Thread(this);
			pipe_thread2.start();
			pipe(in, remote_out);
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	static public void main(String[] args) throws UnknownHostException {
		int port = 5900;
		if (args.length > 0) {
			port = Integer.parseInt(args[0]);
		}
		PipeServer server = new PipeServer();
		server.start(port, 5, InetAddress.getByName("0.0.0.0"));
	}

    public void stop() {
        try {
            if (ss.isBound() && !ss.isClosed()) {
                ss.close();
            }
        } catch (IOException e) {
            log("failed to close server socket. " + e.getMessage());
        }
    }

   public class PipeMessage {
	public int command;
	public String host = null;

	public InetAddress[] ips = null;
	public int[] ports = null;
	public int ipsSize = 0;

	private byte[] msgBytes;
	private int msgLength;

	static final int PIPE_CMD_CONNECT = 0x1;

	static final int PIPE_CMD_NOT_SUPPORTED = 1;

	// request message
	PipeMessage(int command, InetAddress[] ips, int[] ports) {
		this.command = command;
		this.ips = ips;
		this.ports = ports;

		msgLength = ips.length * 6 + 2;
		msgBytes = new byte[msgLength];

		msgBytes[0] = (byte) command;
		msgBytes[1] = (byte) (ips.length);

		int msgP = 2;

		for (int i = 0; i < ips.length; i++) {
			byte[] addr;

			msgBytes[msgP] = (byte) (ports[i] >> 8);
			msgBytes[msgP + 1] = (byte) (ports[i]);
			msgP += 2;

			addr = ips[i].getAddress();
			System.arraycopy(addr, 0, msgBytes, msgP, 4);
			msgP += 4;
		}
	}
	
	PipeMessage(int command, InetAddress[] ips, int[] ports,int offset) {
		this.command = command;
		this.ips = ips;
		this.ports = ports;

		msgLength = (ips.length-offset) * 6 + 2;
		msgBytes = new byte[msgLength];

		msgBytes[0] = (byte) command;
		msgBytes[1] = (byte) (ips.length-offset);

		int msgP = 2;

		for (int i = offset; i < ips.length; i++) {
			byte[] addr;

			msgBytes[msgP] = (byte) (ports[i] >> 8);
			msgBytes[msgP + 1] = (byte) (ports[i]);
			msgP += 2;

			addr = ips[i].getAddress();
			System.arraycopy(addr, 0, msgBytes, msgP, 4);
			msgP += 4;
		}
	}

	// response message
	PipeMessage(int command, int status) {
		this.command = command;

		msgLength = 3;
		msgBytes = new byte[msgLength];

		msgBytes[0] = (byte) command;
		msgBytes[1] = (byte) status;
		msgBytes[msgBytes.length - 1] = 0;
	}

	PipeMessage() {
	}

	public PipeMessage(InputStream in) throws IOException {
		msgBytes = null;
		read(in);
	}

	public void read(InputStream in) throws IOException {
		DataInputStream d_in = new DataInputStream(in);
		command = d_in.readUnsignedByte();

		switch (command) {
		case PipeMessage.PIPE_CMD_CONNECT:
			ipsSize = d_in.readUnsignedByte();
			ips = new InetAddress[ipsSize];
			ports = new int[ipsSize];
			for (int i = 0; i < ipsSize; i++) {
				ports[i] = d_in.readUnsignedShort();
				byte[] addr = new byte[4];
				d_in.readFully(addr);
				ips[i] = bytes2IP(addr);
			}
			break;
		default:
			throw new PipeException(PipeMessage.PIPE_CMD_NOT_SUPPORTED, "Pipe command does not support at reading");
		}
	}

	public void write(OutputStream out) throws IOException {
		if (msgBytes == null) {
			PipeMessage msg = new PipeMessage(command, ips, ports);
			msgBytes = msg.msgBytes;
			msgLength = msg.msgLength;
			
		}
		out.write(msgBytes);
		for (int i=0;i<msgLength;i++) System.err.print(Integer.toHexString(msgBytes[i])+" ");
		System.err.println();
	}

	public int getCommand() {
		return command;
	}

	public void setCommand(int command) {
		this.command = command;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public InetAddress[] getIps() {
		return ips;
	}

	public void setIps(InetAddress[] ips) {
		this.ips = ips;
	}

	public int getIpsSize() {
		return ipsSize;
	}

	public void setIpsSize(int ipsSize) {
		this.ipsSize = ipsSize;
	}

	static InetAddress bytes2IP(byte[] addr) {
		String s = bytes2IPV4(addr, 0);
		try {
			return InetAddress.getByName(s);
		} catch (UnknownHostException uh_ex) {
			return null;
		}
	}

	static final String bytes2IPV4(byte[] addr, int offset) {
		String hostName = "" + (addr[offset] & 0xFF);
		for (int i = offset + 1; i < offset + 4; ++i)
			hostName += "." + (addr[i] & 0xFF);
		return hostName;
	}

	@Override
	public String toString() {
		return "PipeMessage: command=" + command + "\n host=" + host + "\n ips=" + Arrays.toString(ips) + "\n ipsSize=" + ipsSize + "\n ports=" + Arrays.toString(ports) + "\n";}


运行结果:
Accepted from:192.168.6.240:48887
PipeMessage: command=1
host=null
ips=[/192.168.6.240, /192.168.6.39, /192.168.6.240, /192.168.6.39, /192.168.6.245]
ipsSize=5
ports=[5909, 5908, 5909, 5908, 5901]

1 4 17 14 ffffffc0 ffffffa8 6 27 17 15 ffffffc0 ffffffa8 6 fffffff0 17 14 ffffffc0

ffffffa8 6 27 17 d ffffffc0 ffffffa8 6 fffffff5
Connected to /192.168.6.240:5909
Accepted from:192.168.6.240:48889
PipeMessage: command=1
host=null
ips=[/192.168.6.240, /192.168.6.39, /192.168.6.245]
ipsSize=3
ports=[5909, 5908, 5901]

1 2 17 14 ffffffc0 ffffffa8 6 27 17 d ffffffc0 ffffffa8 6 fffffff5
Connected to /192.168.6.240:5909
Accepted from:192.168.6.240:48893
PipeMessage: command=1
host=null
ips=[/192.168.6.245]
ipsSize=1
ports=[5901]

Connected to /192.168.6.245:5901

Connected to /192.168.6.245:5901
Aborting operation
Client to remote,  stopped.
Aborting operation
Aborting operation
Client to remote,  stopped.
Client to remote,  stopped.
Remote to client, stopped
Remote to client, stopped
Remote to client, stopped

   ————————使用VISIO画出UML图解——————
  • VNC.rar (2.9 MB)
  • 下载次数: 35
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics