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这个东西是我自己写的从键盘读一行的工具类 没啥东西 你们需要自己写