java实现的端口映射器
〖 作者:javafound 〗〖 大小:152k 〗〖 發(fā)布日期:2007-05-18 〗〖 瀏覽:0 〗 | ||||
圖1 ????? 因此,A機需實現端口轉發(fā)功能,在Liunx上,可以通過配置IPTable由OS實現,在本例中,我們將開發(fā)一個java實現的端口轉發(fā)程序jPortMap,此程序將運行在A機器上,以實現轉發(fā)C與B之間通信的轉發(fā)。 3.jPortMap程序類的構成說明: Company: www.NetJava.org * @author javafound*/ public class Route {public Route() {}//jPortMap綁定的IPString LocalIP="";//監(jiān)聽的端口int LocalPort=0;//轉發(fā)數據的目標機器IPString DestHost="";//轉發(fā)的目標端口int DestPort=0;//這個轉發(fā)上許可進入的IP列表String AllowClient="";//重寫的toString方法,輸出具體Route對象的信息以便debug public String toString() {StringBuffer stb = new StringBuffer();stb.append(" LocalADD " + LocalIP);stb.append(" :" + LocalPort);stb.append(" --->DestHost " + DestHost);stb.append(" :" + DestPort);stb.append(" (AllowClient) " + AllowClient);return stb.toString();} } ????? 可以比對cfg/jPortMap.cfg(可用notepad打開)中的內容,Route類只需要據文本件中的配配生成多個Route對象或者說轉發(fā)任務,再由其它對象來使用,因此,Route類的功能和結構很簡單,就像映射表結構的javaBean一樣,只是負責保存數據在內存中。 5. SysLog.java解析: SysLog保存每天的日志信息到指定的目錄下,簡單的說就是提供方法供別的對象來調用,寫內容到文件中: package org.netjava.jportmap; import java.io.*; import java.util.Calendar; /*** Title: 端口轉發(fā)器 * Description:日志工具類 * Copyright: Copyright (c) 2005* Company: www.NetJava.org* @author javafound* @version 1.0*/ public class SysLog {//記錄輸出一般信息public static void info(String s) {writeToTodayLog("INFO :", s);}記錄警告信息public static void warning(String s) {writeToTodayLog("WARN:", s);}//記錄錯誤信息 public static void severe(String s) {writeToTodayLog("ERROR:", s);} //輸出到當天日志文件的具體實現private static void writeToTodayLog(String flag, String msg) {RandomAccessFile raf = null;try {Calendar now = Calendar.getInstance();String yyyy = String.valueOf(now.get(java.util.Calendar.YEAR));String mm = String.valueOf(now.get(Calendar.MONTH) + 1);String dd = String.valueOf(now.get(Calendar.DAY_OF_MONTH));String hh = String.valueOf(now.get(Calendar.HOUR_OF_DAY));String ff = String.valueOf(now.get(Calendar.MINUTE));String ss = String.valueOf(now.get(Calendar.SECOND));mm = (1 == mm.length()) ? ("0" + mm) : mm;dd = (1 == dd.length()) ? ("0" + dd) : dd;hh = (1 == hh.length()) ? ("0" + hh) : hh;ff = (1 == ff.length()) ? ("0" + ff) : ff;ss = (1 == ss.length()) ? ("0" + ss) : ss;String yyyymmdd = yyyy + mm + dd;String hhffss=hh+ff+ss;String path = System.getProperties().getProperty("user.dir")+ File.separator + "log";File p = new File(path);if (!p.exists()) {p.mkdirs();}path += File.separator + "jPortMap_" + yyyymmdd + ".log";File f = new File(path);if (f.isDirectory()) {f.delete();}raf = new RandomAccessFile(f, "rw");raf.seek(raf.length());raf.writeBytes(hhffss+" "+flag + " : " + msg + "/r/n");raf.close();} catch (Exception ex) {System.out.println("write file has error=" + ex);}}/** Creates a new instance of SysLog *做為一個工具類,一般不需要實例化,所以此處private*/private SysLog() {} } 說明: public class Server extends Thread {//創(chuàng)建一個轉發(fā)服務器public Server(Route route, int id) {this.route = route;connectionQueue = new Vector();myID = id;start();}//關閉這個服務器:public void closeServer() {isStop = true;if (null != myServer) {closeServerSocket();} while (this.connectionQueue.size() > 0) {Transfer tc = (Transfer) connectionQueue.remove(0);tc.closeSocket(tc.socket);tc = null;}} //啟動轉發(fā)服務器的執(zhí)行線程public void run() {SysLog.info(" start Transfer......:" + route.toString());ServerSocket myServer = null;try {InetAddress myAD = Inet4Address.getByName(route.LocalIP);myServer = new ServerSocket(route.LocalPort, 4, myAD);} catch (Exception ef) {SysLog.severe("Create Server " + route.toString() + " error:" + ef);closeServerSocket();return;}SysLog.info("Transfer Server : " + route.toString() + " created OK");while (!isStop) {String clientIP = "";try {Socket sock = myServer.accept();clientIP = sock.getInetAddress().getHostAddress();if (checkIP(route, clientIP)) {SysLog.warning(" ransfer Server : " + route.toString() +" Incoming:" + sock.getInetAddress());sock.setSoTimeout(0);connCounter++;Transfer myt = new Transfer(sock, route);connectionQueue.add(myt);} else {SysLog.warning(" ransfer Server : " + route.toString() +" Refuse :" + sock.getInetAddress());closeSocket(sock);}} catch (Exception ef) {SysLog.severe(" Transfer Server : " + route.toString() +" accept error" + ef);}}}//檢測進入的IP是否己許可private static boolean checkIP(Route route, String inIP) {String[] inI = string2StringArray(inIP, ".");String[] list = string2StringArray(route.AllowClient, ".");if (inI.length != list.length) {SysLog.severe(" Transfer Server Error Cfg AllowClient : " +route.toString());return false;}for (int i = 0; i < inI.length; i++) {if ((!inI[i].equals(list[i])) && !(list[i].equals("*"))) {System.out.println(": " + inI[i] + " :" + list[i]);return false;}}return true;}/** @param srcString 原字符串* @param separator 分隔符* @return 目的數組*/private static final String[] string2StringArray(String srcString,String separator) {int index = 0;String[] temp;StringTokenizer st = new StringTokenizer(srcString, separator);temp = new String[st.countTokens()];while (st.hasMoreTokens()) {temp[index] = st.nextToken().trim();index++;}return temp;}//關閉ServerSocketprivate void closeServerSocket() {try {this.myServer.close();} catch (Exception ef) {}}private void closeSocket(Socket s) {try {s.close();} catch (Exception ef) {}}//服務器private ServerSocket myServer = null;//連結隊列控制private boolean isStop = false;//private Vector connectionQueue = null;private int connCounter = 0;// 路由對象private Route route = null;//連結的ID號,暫未用private static int myID = 0; }?? Server類關鍵功能是在一個獨立的線程中執(zhí)行監(jiān)聽任務,當我們實例化一個ServerSocket時,即綁定了本機的一個IP和端口,這個ServerSocket對象就在這個地址(由IP和端口組成)上通過調用accept()方法等待客戶端連結,默認情況下,這個等待會一直持續(xù),直到有一個連結進入----生成一個socket對象; 而我們的ServerSocket.accept()是在一個wilhe循環(huán)中,這保證了監(jiān)聽服務器不會中途退出。 7. Transfer.java解析 ????? 在分析Server.java中我們看到,Server做為一個服務器,在與客戶端建立連結后使用生成的Socket對象和自己的Routc對象來實例化一個Transfer,具體的傳輸工作就交給了Transfer對象完成。 ??? Server生成的Socket對象是機器C與A之間連結的一個代碼,通過這個Socekt對象上的Input/OutPut Stream,可以讓C與A之間通信----工作還只完成了一半,這里我們還需要建立A與B之間的Socket連結,這里就出現了兩個Socket連結,分別是C與A間,我們叫SocketCA;A與B間我們假設叫做SocketAB; Transfer對象的任務就是行建立SocketAB,然后,將SocketCA的輸入寫入到SocketAB的輸出流,將SocketAB的輸出流寫到SocketCA的輸出流中,這樣,就完成了C,B機器之間的數據轉發(fā)。 package org.netjava.jportmap; import java.net.*; import java.io.*; /*** Title: 端口轉發(fā)器* Description: 對連結進行轉發(fā)處理* Copyright: Copyright (c) 2005* Company: www.NetJava.org* @author javafound* @version 1.0*/ public class Transfer extends Thread {/*** 創(chuàng)建傳輸對象* @param s Socket :進入的socket* @param route Route:轉發(fā)配置*/public Transfer(Socket s, Route route) {this.route = route;this.socket = s;this.start();}// 執(zhí)行操作的線程public void run() {Socket outbound = null;try {outbound = new Socket(route.DestHost, route.DestPort);socket.setSoTimeout(TIMEOUT);InputStream is = socket.getInputStream();outbound.setSoTimeout(TIMEOUT);OutputStream os = outbound.getOutputStream();pipe(is, outbound.getInputStream(), os, socket.getOutputStream());} catch (Exception e) {SysLog.severe(" transfer error:" +route.toString()+ " :" + e);} finally {SysLog.warning("Disconnect :"+ route.toString());closeSocket(outbound);closeSocket(socket);}}/***傳輸的實現方法*/private void pipe(InputStream is0, InputStream is1,OutputStream os0, OutputStream os1) {try {int ir;byte bytes[] = new byte[BUFSIZ];while (true) {try {if ((ir = is0.read(bytes)) > 0) {os0.write(bytes, 0, ir);} else if (ir < 0) {break;}} catch (InterruptedIOException e) {}try {if ((ir = is1.read(bytes)) > 0) {os1.write(bytes, 0, ir);// if (logging) writeLog(bytes,0,ir,false);} else if (ir < 0) {break;}} catch (InterruptedIOException e) {}}} catch (Exception e0) {SysLog.warning(" Method pipe" + this.route.toString() + " error:" +e0);}}//關閉socketvoid closeSocket(Socket s) {try {s.close();} catch (Exception ef) {}}//傳輸任務的Route對象 Route route = null;// 傳入數據用的Socket Socket socket;//超時static private int TIMEOUT = 1000;//緩存static private int BUFSIZ = 1024; }8.Main.java解析 OK,至此己萬事具備!我們需要一個啟動主類,根據讀入的配置文件數據來啟動轉發(fā)服務器,執(zhí)行轉發(fā)工作: package org.netjava.jportmap; import java.io.*; import java.util.*; import java.net.*; /*** Title: 端口轉發(fā)器* Description:啟動主類:讀取配置,啟動監(jiān)聽服務 * Copyright: Copyright (c) 2005* Company: www.NetJava.org* @author javafound* @version 1.0*/ public class Main {//start......public static void main(String args[]) {startService();} //startpublic static void startService() {if (!loadCfgFile()) {System.exit(1);} while (serverList.size() > 0) {Server ts = serverList.remove(0);ts.closeServer();}for (int i = 0; i < routeList.size(); i++) {Route r = routeList.get(i);Server server = new Server(r, i);serverList.add(server);}} // 停止服務接口,備用其它模塊調用public static void stop() {while (serverList.size() > 0) {Server ts = serverList.remove(0);ts.closeServer();}}/***從配置文件讀取數據,生成Route對象* read cfg parameter* @return boolean*/private static boolean loadCfgFile() {try {String userHome = System.getProperties().getProperty("user.dir");if (userHome == null) {userHome = "";} else {userHome = userHome + File.separator;}userHome += "cfg" + File.separator + "jPortMap.cfg";InputStream is = new FileInputStream(userHome);Properties pt = new Properties();pt.load(is);//共有幾個業(yè)務模塊int ServiceCount = Integer.parseInt(pt.getProperty("TransferCount"));for (; ServiceCount > 0; ServiceCount--) {Route r = new Route();r.LocalIP = pt.getProperty("LocalIP." + ServiceCount).trim();r.LocalPort = Integer.parseInt(pt.getProperty("LocalPort." +ServiceCount).trim());r.DestHost = pt.getProperty("DestHost." + ServiceCount).trim();r.DestPort = Integer.parseInt(pt.getProperty("DestPort." +ServiceCount).trim());r.AllowClient = pt.getProperty("AllowClient." + ServiceCount).trim();routeList.add(r);}is.close();SysLog.info("ystem Read cfg file OK");} catch (Exception e) {System.out.println("找不到配置文件:"+e);SysLog.severe("loadCfgFile false :" + e);return false;}return true;}//Server服務器集合private static List< Server> serverList = new ArrayList();//Route集合private static List< Route> routeList = new ArrayList(); }???? Main類中需要注意的是loadCfgFile()方法,它用來讀取當前目錄下面cfg/jPortMap.cfg文件中的配置數據,如讀取成功,返加ture值,如讀取失敗,程序測會退出。 ?????? 無論如何,這還是個比較簡陋的程序!假如我們把配置改成XML格式、假如我們使用Thread Pool來執(zhí)行任務、假如我們使用NIO、假如我們再做一套PL的UI界面….,您的任何建議,都會是對jPortMap走向完美的支持,請登陸www.NetJava.cn發(fā)表您的看法,發(fā)布您的創(chuàng)新!當然,www.NetJava.cn現在己增加了許多新東東讓您欣賞! |
總結
以上是生活随笔為你收集整理的java实现的端口映射器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 语音识别技术:2018年主要参与者的完整
- 下一篇: 浅谈《分布式光伏发电系统电气安全技术规范