zoukankan      html  css  js  c++  java
  • Java实现端口映射/转发

    20190630 14:57更新

    添加了一个功能 检查当前连接状态 同时发现清除超时连接忘了加定时器 现在清除超时连接可以正常工作了

      1 import java.io.IOException;
      2 import java.io.InputStream;
      3 import java.io.OutputStream;
      4 import java.net.ServerSocket;
      5 import java.net.Socket;
      6 import java.text.SimpleDateFormat;
      7 import java.util.*;
      8 
      9 public class SimpleForward implements Runnable {
     10     // 服务器
     11     private ServerSocket server;
     12     // 监听本地端口
     13     private int localPort = 1080;
     14     // 目标主机地址
     15     private String remoteHostAddr = "0.0.0.0";
     16     // 目标主机端口
     17     private int remoteHostPort = 8388;
     18     // 设置超时时间 30s
     19     private static int TIMEOUT = 30;
     20     // 客户端列表 用于删除失效连接和超时连接
     21     private static HashMap<Socket, Date> clientList = new HashMap<>();
     22 
     23     public static void main(String[] args) throws IOException {
     24 //        new SimpleForward();
     25         new SimpleForward(1234, "127.0.0.1", 1080);
     26     }
     27 
     28     public SimpleForward() throws IOException {
     29         run();
     30     }
     31 
     32     public SimpleForward(int localPort, String remoteHostAddr, int remoteHostPort) throws IOException {
     33         this.localPort = localPort;
     34         this.remoteHostAddr = remoteHostAddr;
     35         this.remoteHostPort = remoteHostPort;
     36         run();
     37     }
     38 
     39     @Override
     40     public void run() {
     41         try {
     42             this.server = new ServerSocket(this.localPort);
     43             System.out.println("服务器开启成功");
     44             System.out.println("监听端口 : " + this.localPort);
     45         } catch (IOException e) {
     46             System.out.println("服务器开启失败");
     47             System.out.println(e.getMessage());
     48             System.out.println("退出运行");
     49             return;
     50         }
     51         // 自动清除失效连接和超时连接
     52         new Thread(new Terminal()).start();
     53         new Thread(new AutoDestroy()).start();
     54         while (true) {
     55             Socket socket = null;
     56             Socket remoteHost = null;
     57             try {
     58                 socket = server.accept();
     59                 // 接收到请求就把socket扔进map,value为刷新时间
     60                 clientList.put(socket, new Date());
     61                 String address = socket.getRemoteSocketAddress().toString();
     62                 System.out.println("新连接 : " + address);
     63                 // 建立与目标主机的连接
     64                 remoteHost = new Socket(this.remoteHostAddr, this.remoteHostPort);
     65                 System.out.println("连接地址 : " + this.remoteHostAddr + ":" + this.remoteHostPort);
     66                 // 端口转发
     67                 new Thread(new Switch(socket, remoteHost, remoteHost.getInputStream(), socket.getOutputStream())).start();
     68                 new Thread(new Switch(socket, remoteHost, socket.getInputStream(), remoteHost.getOutputStream())).start();
     69             } catch (IOException e) {
     70                 System.out.println("连接异常");
     71                 System.out.println(e.getMessage());
     72                 close(socket);
     73                 close(remoteHost);
     74             }
     75         }
     76     }
     77 
     78     private void close(Socket socket) {
     79         try {
     80             if (socket != null) {
     81                 socket.close();
     82             }
     83         } catch (IOException e) {
     84             e.printStackTrace();
     85         }
     86     }
     87 
     88     // 用于端口转发
     89     private class Switch implements Runnable {
     90         private Socket host;
     91         private Socket remoteHost;
     92         private InputStream in;
     93         private OutputStream out;
     94 
     95         Switch(Socket host, Socket remoteHost, InputStream in, OutputStream out) {
     96             this.host = host;
     97             this.remoteHost = remoteHost;
     98             this.in = in;
     99             this.out = out;
    100         }
    101 
    102         @Override
    103         public void run() {
    104             int length = 0;
    105             byte[] buffer = new byte[1024];
    106             try {
    107                 while (!host.isClosed() && (length = in.read(buffer)) > -1) {
    108                     clientList.put(host, new Date());
    109                     out.write(buffer, 0, length);
    110                 }
    111             } catch (IOException e) {
    112                 System.out.println("连接关闭");
    113             } finally {
    114                 close(host);
    115                 close(remoteHost);
    116             }
    117         }
    118     }
    119 
    120     // 用于清除失效连接和超时连接
    121     private class AutoDestroy implements Runnable {
    122 
    123         @Override
    124         public void run() {
    125             Timer timer = new Timer();
    126             timer.schedule(new TimerTask() {
    127                 @Override
    128                 public void run() {
    129                     List<Socket> list = new LinkedList<>();
    130                     System.out.println("开始扫描失效与超时连接");
    131                     Date start = new Date();
    132                     for (Socket socket : clientList.keySet()) {
    133                         Date lastTime = clientList.get(socket);
    134                         long time = new Date().getTime() - lastTime.getTime();
    135                         if (socket.isClosed() || time / 1000 >= TIMEOUT) {
    136                             list.add(socket);
    137                         }
    138                     }
    139                     System.out.println("找到" + list.size() + "个,用时 : " + (new Date().getTime() - start.getTime()) + "毫秒");
    140                     System.out.println("开始清除失效与超时连接");
    141                     for (Socket socket : list) {
    142                         try {
    143                             clientList.remove(socket);
    144                             socket.close();
    145                         } catch (IOException e) {
    146                             e.printStackTrace();
    147                         }
    148                     }
    149                     System.out.println("当前连接数 : " + clientList.size());
    150                 }
    151             }, 30 * 1000, 30 * 1000);
    152         }
    153     }
    154 
    155     private class Terminal implements Runnable {
    156         private ReaderUtil reader = new ReaderUtil();
    157         private String format = "yyyy-MM-dd HH:mm:ss";
    158         private SimpleDateFormat dateFormat = new SimpleDateFormat(format);
    159 
    160         @Override
    161         public void run() {
    162             while (!server.isClosed()) {
    163                 System.out.print("请输入命令 : ");
    164                 String cmd = reader.readKB();
    165                 handler(cmd);
    166             }
    167         }
    168 
    169         private void handler(String cmd) {
    170             switch (cmd) {
    171                 case "status":
    172                     System.out.println("当前时间 : " + dateFormat.format(new Date()));
    173                     System.out.println("总连接数 : " + clientList.size());
    174                     for (Socket socket : clientList.keySet()) {
    175                         long time = new Date().getTime() - clientList.get(socket).getTime();
    176                         System.out.println("<" + socket.getRemoteSocketAddress().toString() + "> " + time / 1000);
    177                     }
    178                     break;
    179             }
    180         }
    181     }
    182 }

     ReaderUtil这个东西是我自己写的从键盘读一行的工具类 没啥东西 你们需要自己写

    来自1942年冬季攻势中的中央集团军的037号17吨救援拖车
  • 相关阅读:
    HDU 4069 Squiggly Sudoku
    SPOJ 1771 Yet Another NQueen Problem
    POJ 3469 Dual Core CPU
    CF 118E Bertown roads
    URAL 1664 Pipeline Transportation
    POJ 3076 Sudoku
    UVA 10330 Power Transmission
    HDU 1426 Sudoku Killer
    POJ 3074 Sudoku
    HDU 3315 My Brute
  • 原文地址:https://www.cnblogs.com/panther1942/p/11109575.html
Copyright © 2011-2022 走看看