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";// 与客户端相连的Socketprotected 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);elselog_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"; // 读取请求URLString host = ""; // 读取目标主机hostint port = 80; // 默认端口80Socket 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;// 抽取hostn = 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 minutesstatic 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);}}@Overridepublic 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 messagePipeMessage(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 messagePipeMessage(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;}@Overridepublic 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图解——————