代码如下:

    import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.CountDownLatch; /**
* Created with Intellij IDEA
*
* @author: jiaoyiping
* Mail: jiaoyiping@gmail.com
* Date: 2018/03/01
* Time: 22:08
* To change this template use File | Settings | Editor | File and Code Templates
*/ public class MySocket5Server implements Runnable {
private static final int SOCKS_PROTOCOL_4 = 0X04;
private static final int SOCKS_PROTOCOL_5 = 0X05;
private static final int DEFAULT_BUFFER_SIZE = 1024;
private static final byte TYPE_IPV4 = 0x01;
private static final byte TYPE_IPV6 = 0X02;
private static final byte TYPE_HOST = 0X03;
private static final byte ALLOW_PROXY = 0X5A;
private static final byte DENY_PROXY = 0X5B;
private Socket sourceSocket; @Override
public void run() {
String remoteAddress = sourceSocket.getRemoteSocketAddress().toString();
log("process socket:" + remoteAddress);
InputStream sourceIn = null, proxyIn = null;
OutputStream sourceOut = null, proxyOut = null; Socket proxySocket = null;
try {
sourceIn = sourceSocket.getInputStream();
sourceOut = sourceSocket.getOutputStream();
//从协议头中获取socket的类型
byte[] tmp = new byte[1];
int n = sourceIn.read(tmp);
if (n == 1) {
int protocol = tmp[0];
//socket4
if (SOCKS_PROTOCOL_4 == protocol) {
proxySocket = convertToSocket4(sourceIn, sourceOut); } else if (SOCKS_PROTOCOL_5 == protocol) {
proxySocket = convertToSocket5(sourceIn, sourceOut);
} else {
log("Socket协议错误,不是Socket4或者Socket5");
}
//socket转换
if (null != proxySocket) {
CountDownLatch countDownLatch = new CountDownLatch(1);
proxyIn = proxySocket.getInputStream();
proxyOut = proxySocket.getOutputStream();
transfer(sourceIn, proxyOut, countDownLatch);
transfer(proxyIn, sourceOut, countDownLatch);
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
} } } else {
log("SOCKET ERROR: " + tmp.toString());
} } catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(sourceIn);
closeIO(proxyIn);
closeIO(proxyOut);
closeIO(proxyIn);
closeIO(proxySocket);
closeIO(sourceSocket);
} } public MySocket5Server(Socket sourceSocket) {
this.sourceSocket = sourceSocket;
} private static final void log(String message) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateFormat.format(new Date()) + " - " + message);
} private static void startServer(int port) {
log("config =>> port=" + port);
try (ServerSocket serverSocket = new ServerSocket(port)) {
Socket socket = null;
while ((socket = serverSocket.accept()) != null) {
new Thread(new MySocket5Server(socket)).start();
}
log("close socket(this never happen)");
} catch (IOException e) {
e.printStackTrace();
} } private Socket convertToSocket4(InputStream inputStream, OutputStream outputStream) throws IOException {
Socket proxySocket = null;
byte[] tmp = new byte[3];
inputStream.read(tmp);
// 请求协议|VN1|CD1|DSTPORT2|DSTIP4|NULL1|
int port = ByteBuffer.wrap(tmp, 1, 2).asShortBuffer().get() & 0xFFFF;
String host = getHost((byte) 0x01, inputStream);
inputStream.read();
//返回一个8字节的响应协议: |VN1|CD1|DSTPORT2|DSTIP 4|
byte[] response = new byte[8];
try {
proxySocket = new Socket(host, port);
response[1] = ALLOW_PROXY;
log("connect " + tmp[1] + "host: " + host + " ,port: " + port);
} catch (Exception e) {
response[1] = DENY_PROXY;
log("connect error,host: " + host + " ,port: " + port);
}
outputStream.write(response);
outputStream.flush(); return proxySocket;
} private Socket convertToSocket5(InputStream inputStream, OutputStream outputStream) throws IOException {
Socket proxySocket = null;
//处理SOCKS5头信息(不支持登录)
byte[] tmp = new byte[2];
inputStream.read(tmp);
byte method = tmp[1];
if (0x02 == tmp[0]) {
method = 0x00;
inputStream.read();
}
tmp = new byte[]{0x05, method};
outputStream.write(tmp);
outputStream.flush(); byte cmd = 0;
tmp = new byte[4];
inputStream.read(tmp);
log("proxy header is:" + Arrays.toString(tmp)); cmd = tmp[1];
String host = getHost(tmp[3], inputStream);
tmp = new byte[2];
inputStream.read(tmp);
int port = ByteBuffer.wrap(tmp).asShortBuffer().get() & 0xFFFF;
log("connect host: " + host + " :port:" + port);
ByteBuffer rsv = ByteBuffer.allocate(10);
rsv.put((byte) 0x05);
Object resultTmp = null;
try {
if (0x01 == cmd) {
resultTmp = new Socket(host, port);
rsv.put((byte) 0x00);
} else if (0x02 == cmd) {
resultTmp = new ServerSocket(port);
rsv.put((byte) 0x00);
} else {
rsv.put((byte) 0x05);
resultTmp = null;
}
} catch (Exception e) {
rsv.put((byte) 0x05);
resultTmp = null;
}
rsv.put((byte) 0x00);
rsv.put((byte) 0x01);
rsv.put(sourceSocket.getLocalAddress().getAddress());
Short localPort = (short) ((sourceSocket.getLocalPort()) & 0xFFFF);
rsv.putShort(localPort);
tmp = rsv.array(); outputStream.write(tmp);
outputStream.flush();
if (null != resultTmp && 0x02 == cmd) {
ServerSocket ss = (ServerSocket) resultTmp;
try {
resultTmp = ss.accept();
} catch (Exception e) {
} finally {
closeIO(ss);
}
}
return (Socket) resultTmp; } private void transfer(InputStream in, OutputStream out, CountDownLatch latch) {
new Thread(() -> {
byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
int count = 0;
try {
while (0 < (count = in.read(bytes))) {
out.write(bytes, 0, count);
out.flush();
}
} catch (IOException e) {
log("转换出现错误");
e.printStackTrace();
}
if (latch != null) {
latch.countDown();
} }).start(); } private void closeIO(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} private String getHost(byte type, InputStream inputStream) throws IOException {
String host = null;
byte[] tmp = null;
switch (type) {
case TYPE_IPV4:
tmp = new byte[4];
inputStream.read(tmp);
host = InetAddress.getByAddress(tmp).getHostAddress();
break;
case TYPE_IPV6:
tmp = new byte[16];
inputStream.read(tmp);
host = InetAddress.getByAddress(tmp).getHostAddress();
break;
case TYPE_HOST:
int count = inputStream.read();
tmp = new byte[count];
inputStream.read(tmp);
host = new String(tmp);
default:
break;
}
return host;
} public static void main(String[] args) {
java.security.Security.setProperty("networkaddress.cache.ttl", "86400");
MySocket5Server.startServer(1033);
} }

使用java实现的socket代理(支持socket4和socket5)的更多相关文章

  1. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

  2. java网络编程socket解析

    转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在 ...

  3. 读懂Java中的Socket编程

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

  4. 读懂Java中的Socket编程(转)

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

  5. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  6. Java学习笔记--动态代理

    动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...

  7. Confluence 6 配置 Web 代理支持

    这个页面中的相关平台中的内容是不被支持的.因此,Atlassian 支持不能保证能够为你提供任何支持.请注意,这个页面下面提供的信息仅为你提供参考同时也不能保证所有的的配置能正常工作.如果你按照本页面 ...

  8. 杨晓峰-Java核心技术-6 动态代理 反射 MD

    目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...

  9. java中的socket编程

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

随机推荐

  1. 软件设计模式之代理模式(JAVA)

    貌似停笔了近半个月了,实在不该啊,新的一年,时刻让自己归零. Back To Zero,就从这篇文章拉开今年的序幕吧. 这篇文章准备介绍下有关代理模式的基本概念和静态代理.动态代理的优缺点及使用方法( ...

  2. ADCD 1.9 ZOS 配置 CTCI-W32 TCPIP 网络

    试验步骤:两步走,第一步修改Hercules的配置文件 在hercules 配置文件末尾加上    0E20-0E21 CTCI     -n 0A-00-27-00-00-00  192.168.5 ...

  3. SQL备份一张表的数据

    使用如下语句 SELECT  *  into   table_bak   FROM   table 可把表table中的数据备份到  table_bak   ,而且无需重新建table_bak .会自 ...

  4. MongoDB 连接池

    http://www.cnblogs.com/huangfox/archive/2012/04/01/2428947.html http://www.iteye.com/problems/97350

  5. ZTree async中文乱码,ZTree reAsyncChildNodes中文乱码,zTree中文乱码

    ZTree async中文乱码,ZTree reAsyncChildNodes中文乱码,zTree中文乱码 >>>>>>>>>>>&g ...

  6. 【GIS】GDAL Python 影像裁剪

    # -*- coding: utf-8 -*- """ Created on Fri Nov 30 11:45:03 2018 @author: Administrato ...

  7. centos 7 安装 gcc-4.9.3.tar.gz

    由于编译新内核需要,更新了GCC编译器,自行获取文件,手动升级. 首先是获取文件:wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gc ...

  8. django学习笔记:AdminSite界面配置

    (一)重定义字段顺序: 修改对应应用目录下的admin.py class PollAdmin(admin.ModelAdmin):     fields = ['pub_date', 'questio ...

  9. iOS开发-- 使用NSNumber将int、float、long等数据类型加入到数组或字典中

    // 设置值 NSNumber *number=[NSNumber numberWithInt:45]; // 取值 NSLog(@"NSNumber %d",[number in ...

  10. 使用Xcode自带的单元测试

    今年苹果推出的iOS8和Swift的新功能让人兴奋.同时,苹果对于Xcode的测试工具的改进却也会影响深远.现在我们来看下XCTest,Xcode内置的测试框架.以及,Xcode6新增的XCTestE ...