使用node.js+netty实现内网穿透

1、Java基于Netty的服务端源码

参照:JAVA基于Netty实现内网穿透功能【设计实践】
代码实现比较清晰,经测试可以正常使用。

2、基于node.js的客户端源码

本客户端源码通过适配Java服务端源码实现。

// 服务器-客户端 通信报文格式:
// 4字节长度+1字节type+x字节data,长度为数据的总长度=4+1+x
// Uint8Array的每个元素为1个字节
var net = require('net');
const client = new net.Socket();
// 服务器端口
const serverPort = 9000;
// 需要被转发的本地服务的端口
const localPort = 8000;

// 客户端连接服务器
client.connect(serverPort, '127.0.0.1', function () {
    client.write(new Uint8Array([0, 0, 0, 5, 1]));
    setHeartBeat(client)
});

// 计算报文长度
function getDataLen(data) {
    return data[0] * 16 * 16 * + data[1] * 16 * 16 + data[2] * 16 + data[3];;
}

// 16进制字符串转10进制整数
function hex2int(hex) {
    if (hex == null || hex == "0") {
        return 0;
    }
    var len = hex.length, a = new Array(len), code;
    for (var i = 0; i < len; i++) {
        code = hex.charCodeAt(i);
        if (48 <= code && code < 58) {
            code -= 48;
        } else {
            code = (code & 0xdf) - 65 + 10;
        }
        a[i] = code;
    }

    return a.reduce(function (acc, c) {
        acc = 16 * acc + c;
        return acc;
    }, 0);
}

// 获取16进制字符串的某一位数字
function getNumFromHex(hexStr, index) {
    if (index < 0 || index >= hexStr.length) {
        return 0;
    }
    return hexStr[index];
}

// 为报文设置长度属性
function setLen(len, uint8Array) {
    // 长度转为16进制
    var str16 = len.toString(16);
    // 16进制长度,拆成4字节存储
    uint8Array[0] = hex2int(getNumFromHex(str16, str16.length - 8) + getNumFromHex(str16, str16.length - 7));
    uint8Array[1] = hex2int(getNumFromHex(str16, str16.length - 6) + getNumFromHex(str16, str16.length - 5));
    uint8Array[2] = hex2int(getNumFromHex(str16, str16.length - 4) + getNumFromHex(str16, str16.length - 3));
    uint8Array[3] = hex2int(getNumFromHex(str16, str16.length - 2) + getNumFromHex(str16, str16.length - 1));
}

// 客户端接收服务器数据
client.on('data', function (data) {
    var type = data[4];
    var len = getDataLen(data);
    if (type == 0) {
        return;
    }
    console.log('新数据长度:' + len);
    console.log('新数据type:' + type);
    console.log("新数据:" + data.toString());
    // 客户端与服务器成功连接
    if (type == 1) {
        const worker = new net.Socket();
        worker.connect(serverPort, '127.0.0.1', function () {
            var uu = new Uint8Array(data);
            worker.write(uu);
            setHeartBeat(worker)
        });
        worker.on('data', function (data) {
            var type = data[4];
            // 处理server请求
            if (type == 2) {
                handleRequest(data, worker);
            }
        });
        worker.on('close', function () {
            worker.write(new Uint8Array([0, 0, 0, 5, 9]));
            worker.destroy();
        });
        worker.on('error', function (data) {
            console.log('worker error:' + data.toString());
        });

    }
});

function handleRequest(data, worker) {
    const browser = new net.Socket();
    browser.connect(localPort, '127.0.0.1', function () {
        // printU8(data.subarray(5));
        browser.write(new Uint8Array(data.subarray(5)));
    });
    browser.on('data', function (data) {
        // console.log('browser:' + data.toString());
        console.log('browserLen:' + data.length);
        // 转发内网数据到server
        var dataLen = data.length;
        var uint8Array = new Uint8Array(dataLen + 5);
        // 设置报文长度
        setLen(dataLen + 5, uint8Array);
        uint8Array[4] = 2;
        for (var i = 5; i < uint8Array.length; i++) {
            uint8Array[i] = data[i - 5];
        }
        console.log("worder return data:");
        printU8(uint8Array);
        worker.write(uint8Array);
    });
    browser.on('close', function () {
        browser.destroy();
    });
    browser.on('error', function (data) {
        console.log('browser error:' + data.toString());
    });
}

// 打印Uint8Array对象
function printU8(uint8Array) {
    var str = '';
    for (var i = 0; i < 5; i++) {
        str = str + uint8Array[i] + ",";
    }
    for (var i = 5; i < uint8Array.length; i++) {
        str += String.fromCharCode(uint8Array[i]);
    }
    console.log("u8:" + str);
}

// 为client配置心跳
function setHeartBeat(socketClient) {
    setInterval(function () {
        socketClient.write(new Uint8Array([0, 0, 0, 5, 0]));
    }, 10000);
}

client.on('error', function (data) {
    console.log('error:' + data.toString());
});

client.on('close', function () {
    client.write(new Uint8Array([0, 0, 0, 5, 9]));
    client.destroy();
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值