hpsocket做一个tcp转发器

By money at 2021-11-13 • 0人收藏 • 250人看过

没智能提示的库就是垃圾,哈哈,这个库缺少灵魂。

import hpsocket.tcpAgent;
import hpsocket.tcpServer;
import thread.event;

namespace hpsocket;

class tcpProxy{
    /*
    config={
    	localIP="0.0.0.0"; 
    	localPort=99; 
    	proxy={
    		ip="";  //固定的转发IP和端口
    		port=0; 
    		handleRecv=function(direction, str){};//返回修改后的内容 发送
    		handleConnection=function(evt, arg, extraTab){}//evt:accept返回转发的ip port ,evt:close不需要返回
    	};
    }
    */
    ctor( config){
    	config.localIP:="0.0.0.0";
    	if(!config.localPort){
    		error("localPort不能为空"); 
    	}
    	if(!config.proxy){
    	    error("config 缺少proxy参数"); 
    	}
    	if(config.proxy.handleRecv and type(config.proxy.handleRecv)!=type.function){
    		return null, "handleRecv必须为function"; 
    	}
    	if(config.proxy.handleConnection){
    		if(type(config.proxy.handleConnection)!=type.function){
    		    return null, "handleConnection必须为function";
    		}
    	}elseif(!config.proxy.ip or !config.proxy.port) {
    		return null, "ip,port不能为空"; 
    	}
    	
    	this.agent = ..hpsocket.tcpAgent();
    	this.server = ..hpsocket.tcpServer();
    	this.server.setAcceptSocketCount(2000)
    	
		this.agent.onThreadCreated = function(){
			import console;
			import thread.event;
			import hpsocket.tcpServer;
			import thread.command;
			import wsock;
			import time.performance;
			class context{
				int serverid;
				int agentid;
				int index;
				int ip;
				WORD port;
			}
			log = function(...){
				thread.lock("proxy_log")
				..console.dump(...)
				thread.unlock("proxy_log")
			}
			_hpTcpServer = hpsocket.tcpServer(_serverSocket);
		}
		this.agent.threadGlobal = {
   			_serverSocket = this.server.pSocket;
   			_config = config;
   			hasHandleRecv = config.proxy and type(config.proxy.handleRecv)==type.function;
   			hasHandleConnection = config.proxy and type(config.proxy.handleConnection)==type.function;
   			handleConnection = config.proxy.handleConnection;
   			handleRecv = config.proxy.handleRecv;
   			ip = config.proxy.ip;
   			port = config.proxy.port;
		}
		//连接成功触发
		this.agent.onConnect = function(hpTcpAgent,connId){
			//这里一定要等待extra
			while(!hpTcpAgent.getConnectionExtra(connId)){
				sleep(1)
			}
			//给server发送连接事件信号
			var evt = thread.event("agent_"++connId)
			evt.set()
		}
		this.agent.onReceive = function(hpTcpAgent,connId,pData,length){
			var exta = hpTcpAgent.getConnectionExtra(connId);
			var tab=context();
			tab = ..raw.convert(exta,tab)
			
			//转发数据给server,通过server转转发到近端
			//handleRecv函数可以修改发送前的数据
			if(handleRecv){
				var data = ..raw.tostring(pData,1,length)
    			data = handleRecv("remoteToLocal", data, tab)
    			_hpTcpServer.send(tab.serverid, data, #data)
    		}else {
    			_hpTcpServer.send(tab.serverid, pData, length)
    		}
		}
		this.agent.onClose = function(hpTcpAgent,connId,enOperation,errCode){
    		var extra = hpTcpAgent.getConnectionExtra(connId);
    		if(extra){
    			var tab = context();
				tab = ..raw.convert(extra,tab)
				if(handleConnection){
    				handleConnection("close", errCode, tab)
    			}
    			
    			//非正常关闭,server可能还在等待agent连接,给server发送信号
				var evt = thread.event("agent_"++connId)
				evt.set()
    			
				//断开对应的server连接
				_hpTcpServer.disconnect(tab.serverid)	
    		}else {
    			log("agent.onClose,无exta", connId)
    		}
		}
		
		this.server.onThreadCreated = function(){
			import console;
			import thread.event;
			import hpsocket.tcpAgent;
			import thread.command;
			import wsock;
			class context{
				int serverid;
				int agentid;
				int index;
				int ip;
				WORD port;
			}
			log = function(...){
				thread.lock("proxy_log")
				..console.dump(...)
				thread.unlock("proxy_log")
			}
			_hpTcpAgent = hpsocket.tcpAgent(_agentSocket)
		}
		this.server.threadGlobal = {
   			_agentSocket = this.agent.pSocket;
   			_config = config;
   			hasHandleRecv = config.proxy and type(config.proxy.handleRecv)==type.function;
   			hasHandleConnection = config.proxy and type(config.proxy.handleConnection)==type.function;
   			handleConnection = config.proxy.handleConnection;
   			handleRecv = config.proxy.handleRecv;
   			ip = config.proxy.ip;
   			port = config.proxy.port;
		}
		this.server.onShutdown = function(hpTcpServer){
			//断开所有agent连接
			_hpTcpAgent.disconnectSilenceConnections(1,true)
		}
		this.server.onAccept = function(hpTcpServer,connId,pClient){
    		//本地端口收到连接后  agent立即建一个远端连接
    		var ip,port,index
    		if(hasHandleConnection){
    		    ip, port, index = handleConnection("accept")
    		}else {
    			ip, port = ip, port;
    		}
    		
    		if(ip and port){
    			var tab=context();
    			tab.serverid = connId;
    			tab.index = index:0;
    			tab.ip = wsock.htonl(..wsock.inet_addr( ip ))
    			tab.port = port;
    			
    			var pExtra = hpTcpServer.getConnectionExtra(connId)
    			pExtra = ..raw.realloc(..raw.sizeof(tab), pExtra, s)
    			
    			hpTcpServer.setConnectionExtra(connId, pExtra)
    			var id = _hpTcpAgent.connect(ip, port);
    			
    			if(id){
    			    _hpTcpAgent.setConnectionExtra(id, pExtra)
    			   
    				tab.agentid = id;
    				..raw.convert(tab, pExtra);
    				
    				var evt2 = thread.event("agent_"++id);
    				if(!evt2.wait(2000)){
    				    evt2.close()
    					_hpTcpAgent.disconnect(id, true)
    					return 2; 
    				}
    				evt2.close()
    			}else {
    				return 2; 
    			}
    		}
    		return 0; 
		}
		this.server.onReceive = function(hpTcpServer,connId,pData,length){
			var exta = hpTcpServer.getConnectionExtra(connId);
			if(exta){
				var tab=context();
				tab = ..raw.convert(exta,tab)
				
				//转发数据给agent,通过agent转换到远端
				//handleRecv函数可以修改发送前的数据
				if(handleRecv){
					var data = ..raw.tostring(pData,1,length)
    				data = handleRecv("localToRemote", data)
    				_hpTcpAgent.send(tab.agentid, data, #data)
    			}else {
    				_hpTcpAgent.send(tab.agentid, pData, length)
    			}	
			}else {
				log("server.onReceive,无agent", connId)
				return 2; 
			}
		}
		this.server.onClose = function(hpTcpServer,connId,enOperation,errCode){
    		var exta = hpTcpServer.getConnectionExtra(connId);
    		if(exta){
    			var tab=context();
				tab = ..raw.convert(exta,tab)
				//断开对应的agent连接
				_hpTcpAgent.disconnect(tab.agentid)	
				
				//清空extra
				..raw.realloc(0, exta)
    		}else {
    			log("server.onClose,无exta", connId)
    		}
    		
		}
		this.server.onPrepareListen = function(hpTcpServer,soListen){
    		//开始监听(重起监听)后,清理超时的agent连接
    		_hpTcpAgent.disconnectSilenceConnections(90000);
		}
		
    	this.start = function(){
    		var err
    		if(this.server.start(config.localIP,config.localPort)){
				if(this.agent.start()){
					return true; 
				}else {
					err="agent启动失败"	
				}
			}else {
				err="近端监听端口失败"
			}
			return false, err; 
    	}
    	
    	this.stop=function(){
    		this.agent.stop();
    		this.server.stop();
    	}
    };
}

库出来了,没有相关使用说明,做一个demo演示一下。用它做一个HttpProxy吧,动态转发挺方便的,安排上

server端:

import console; 
import win;
import hpsocket.httpServer;
import hpsocket.tcpProxy;

console.open();

//换IP线程
thread.invoke( 
	function(){
		import inet.whttpEx;
		import console;
		import thread.command;
		import win;
		
		var proxies={};
		var index=0;
		var proxyUse={};
		
		//需要定制自己的fetch函数,主要实现从API中取IP出来备用
		fetchProxy1=function(){
			try{
				var http = inet.whttpEx();
				//这里用了一家代理IP,就不贴上来了
				var str = http.get("http://www.3daili.top:9091/orderIp/********&jg=0&num=200&lx=A&proxy=http&gs=txt");
				if(#str>100){
					var tab = string.splitEx(str,"<\r\n>");
					for(i=1;#tab;1){
						table.push(proxies, tab[i])
					}
				}
			}
			catch(e){
				console.dump(e)
			}
		}
		
	
		var cmd = thread.command();
		cmd.delProxy = function(proxy, reason){
			console.dump("删除IP",proxy, reason)
			
			if(!string.indexOf(proxy,':')){
				proxy = proxy+':'
			}
			var k = table.find(proxies, function(v, k, tab){
				if(string.indexOf(v, proxy)){
					return true; 
				}
			})
			if(k){
				table.remove(proxies, k)
			}
		}
		
		cmd.getProxy = function(){
			if(#proxies<20){
				fetchProxy1()
			}
			if(#proxies){
				index++;
				if(index>#proxies){
					index=1
				}
				var proxy = proxies[index]
				if(proxy){
					if(!proxyUse[proxy]){
						proxyUse[proxy]=1
					}else {
						proxyUse[proxy] = proxyUse[proxy]+1
					}
					//限制同一IP只使用5次
					if(proxyUse[proxy]>5){
						table.removeByValue(proxies, proxy)
					}
				}
				//console.dump("取出IP",proxy)
				return proxy; 
			}
		}
		
		import win.timer;
		var timer = win.timer(winform,10000);
		timer.onTimer = function(){ 
			var http = inet.whttpEx();
			http.post(whiteurl, "")
		}
		timer.enable();
		
		fetchProxy1()
		
		win.loopMessage()
	}
)

handleConnection = function(evt, arg, tab){
	if(evt == 'accept'){
		var proxy = thread.command.getProxy();
		if(#proxy){
			var arr = string.split(proxy, ':')
			//return "192.168.32.1", 5000; 
			return arr[1], tonumber(arr[2])
		}
	}elseif(evt == 'close'){
		if(arg){
			var ip = wsock.inet_ntoa(wsock.ntohl(tab.ip))
			var port = tab.port;
			
			thread.command.delProxy(string.format("%s:%d", ip, port), "IP失效");
		}
	}
}
handleRecv = function(evt, data, tab){
	//http还好,可以拦截处理,如果是HTTPS就不行了,所以基本上这里判断是没什么用的
	//所以在下面另开了一个8082端口专用于删除不可用的IP
	if(evt == 'remoteToLocal'){
		if(string.indexOf(data, 'Access Denied')){
			var ip = wsock.inet_ntoa(wsock.ntohl(tab.ip))
			var port = tab.port;
			
			thread.command.delProxy(string.format("%s:%d", ip, port), "IP限制");
		}
	}
	return data; 
}

var ser,err = hpsocket.tcpProxy({
	localIP="0.0.0.0"; 
    localPort=8081; 
    proxy={
    	ip=""; 
    	port=0; 
    	//handleRecv=handleRecv;
    	handleConnection=handleConnection
    };
})

console.dump(err)
console.dump(ser.start())

//另开一个端口,开放一个用于删除指定IP的功能
var hpHttpServer = hpsocket.httpServer();
hpHttpServer.onThreadCreated = function(){	
	import inet.whttpEx;
	import thread.command;
	
}
hpHttpServer.onHeadersComplete = function(hpHttpServer,connId){
	hpHttpServer.reallocString(connId,hpHttpServer.getContentLength(connId))
}
hpHttpServer.onBody = function(hpHttpServer,connId,pData,len){
	hpHttpServer.appendString(connId,pData,len)
}
hpHttpServer.onMessageComplete = function(hpHttpServer,connId){
	var proxy = hpHttpServer.getString(connId);
	if(#proxy){
		thread.command.delProxy(proxy, "IP限制");
	}
	
	hpHttpServer.sendResponse(connId,"OK",{
		["Content-Type"] = "text/html; charset=UTF-8"; 
	});
}

hpHttpServer.start("0.0.0.0", 8082)

win.loopMessage();

嗯,再来个简单的client测试一下

import console; 
import inet.whttp;
import win;

console.open();

//来吧,暴力测试一下
for(i=1;200;1){
	thread.invoke( 
		function(){
			import inet.whttp;
			import console;
			
			for(i=1;999999;1){
				var http = inet.whttp(,"HTTP://127.0.0.1:8081")
				console.dump(i, http.get("某个获取IP的地址"))
			}
			
		}
	)

}


win.loopMessage()

就缺两张图了
image.png

嗯,好像哪里不对,没有安全验证啊?就这样吧

1 个回复 | 最后更新于 2021-11-13
2021-11-13   #1

网络相关的还没研究过, 谢谢分享, 学习了.

登录后方可回帖

登 录
信息栏
本站永久域名:HtmLayout.Cn
aardio可以快速开发上位机,本站主要记录了学习过程中遇到的问题和解决办法及aardio代码分享

这里主要专注于aardio学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.

AARDIO语言QQ群:70517368
Aardio 官方站:Aardio官方
Aardio最新功能:Aardio官方更新日志
C大Aardio论坛:Aar爱好者论坛
本 站 主 站:Stm32cube中文网
Sciter中文在线文档Sciter在线学习文档
赞助商:才仁机械
Loading...