hpsocket做一个tcp转发器

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

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

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

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

2 个回复 | 最后更新于 2023-03-27
2021-11-13   #1

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

2023-03-27   #2


感谢楼主的代码,想请教一下楼主这个库代码是怎么写出来的,有什么关于hpTcpServer完整的库写法可以参考吗?

            class context{
                int serverid;
                int agentid;
                int index;
                int ip;
                WORD 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)

为什么我就不知道应该这样写呢

最近也在学习hpTcpServer的玩法,有些用法不是很明白。

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...