none
请教一个功能实现:通过程序,转发特定端口的数据 RRS feed

  • 问题

  • 一台主机,软件A开放了8080端口

    我想写一个程序B,实现这样一个功能:B程序开放一个7000的端口,将此端口接受的所有数据都转发到A软件的8080端口上。

    这个程序应该用什么技术做,如果能提供一下关键代码/资料最佳(不太明白如何将数据流无损的转发给另外一个链接)

    谢谢~

    2011年4月22日 7:32

答案

  •  

    这是测试代码,目的是把程序运行所在机器的89号端口中继到202.103.11.22的80端口上:
    
    class Program
    	{
    		static void Main(string[] args)
    		{
    			Console.WriteLine("start : start test");
    			Console.WriteLine("stop : stop test");
    			Console.WriteLine("quit : quit this program");
    
    			RelayListener relay = new RelayListener();
    			relay.Port = 89;
    			relay.DestIP = IPAddress.Parse("202.103.11.22");
    			relay.DestPort = 80;
    			relay.AddAllowIP("127.0.0.1");
    
    			string strRead;
    			do
    			{
    				Console.Write(">");
    				strRead = Console.ReadLine();
    
    				if (strRead == "start")
    				{
    					relay.Start();
    					Console.WriteLine("Start at port {0} -> {1}:{2}", relay.Port, relay.DestIP, relay.DestPort);
    				}
    				else if (strRead == "stop")
    				{
    					relay.Stop();
    					Console.WriteLine("Listener has stopped.");
    				}
    
    			} while (strRead != "quit");
    		}
    	}
    下面是中继监听器的实现:
    public class RelayListener
    	{
    		public RelayListener()
    		{
    			m_evCanExit = new EventWaitHandle(false, EventResetMode.ManualReset);
    			m_actListen = Listen;
    			m_epDest = new IPEndPoint(IPAddress.None, 0);
    			//m_confirm = new SecurityConfirm();
    			m_listSR = new List<SocketRelay>();
    		}
     
    		// 中继侦听端口
    		public int Port { get; set; }
     
    		// 中继目标IP
    		public IPAddress DestIP
    		{
    			get { return m_epDest.Address; }
    			set { m_epDest.Address = value; }
    		}
     
    		// 中继目标端口
    		public int DestPort
    		{
    			get { return m_epDest.Port; }
    			set { m_epDest.Port = value; }
    		}
     
    		public void AddAllowIP(string strIP)
    		{
    			//m_confirm.AddAllowIP(strIP);
    		}
     
    		public void Start()
    		{
    			lock (m_actListen)
    			{
    				// 已存在一个监听,避免重复开启
    				if ((m_arListen != null) && (!m_arListen.IsCompleted)) return;
    				m_evCanExit.Reset();
    				m_arListen = m_actListen.BeginInvoke(null, null);
    			}
    		}
     
    		public void Stop()
    		{
    			lock (m_actListen)
    			{
    				// 没有活动的监听
    				if (m_arListen == null || m_arListen.IsCompleted) return;
    				m_evCanExit.Set();
    				m_actListen.EndInvoke(m_arListen);
    				lock(m_listSR) m_listSR.Clear();
    			}
    		}
     
    		private void Listen()
    		{
    			EventWaitHandle evAccept = new EventWaitHandle(false, EventResetMode.ManualReset);
     
    			// IPv4 TCP
    			using (Socket socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
    			{
    				IPEndPoint ep = new IPEndPoint(IPAddress.Any, Port);
    				socketListener.Bind(ep);
    				socketListener.Listen(5);
     
    				WaitHandle[] waits = new WaitHandle[]
    				{
    					m_evCanExit,
    					evAccept
    				};
     
    				int nWait;	// 等待结果
    				do
    				{
    					evAccept.Reset();
    					AsyncCallback ac = AcceptCallback;
    					Tuple<Socket, EventWaitHandle> state = new Tuple<Socket, EventWaitHandle>(socketListener, evAccept);
    					socketListener.BeginAccept(ac, state);
    					nWait = WaitHandle.WaitAny(waits);
    				}
    				while (nWait != 0);
     
    				socketListener.Close();
    			}
    		}
     
    		private void AcceptCallback(IAsyncResult ar)
    		{
    			Socket sktActive = null;
    			try
    			{
    				var state = (Tuple<Socket, EventWaitHandle>)ar.AsyncState;
    				state.Item2.Set();
    				sktActive = state.Item1.EndAccept(ar);
    			}
    			catch (ObjectDisposedException)
    			{
    				// Accept has been cancelled.
    				return;
    			}
     
    			try
    			{
    				// 安全验证
    				//if (!m_confirm.Confirm(sktActive))
    				//{
    				//	sktActive.Close();
    				//	return;
    				//}
     
    				Socket sktPassive = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    				sktPassive.Connect(m_epDest);
     
    				SocketRelay relay = new SocketRelay(sktActive, sktPassive);
    				relay.OnFinished += OnSocketRelayFinished;
    				relay.Run();
    				lock(m_listSR) m_listSR.Add(relay);
    			}
    			catch (SocketException ex)
    			{
    				string strbuf = String.Format("{0}({1})", ex.Message, ex.ErrorCode);
    				byte[] buf = Encoding.Default.GetBytes(strbuf);
    				sktActive.Send(buf);
     
    				sktActive.Shutdown(SocketShutdown.Both);
    				sktActive.Close();
    			}
    		}
     
    		private void OnSocketRelayFinished(SocketRelay item)
    		{
    			lock (m_listSR)
    			{
    				if(m_listSR.Contains(item))
    					m_listSR.Remove(item);
    			}
    		}
     
    		// 侦听Action
    		private Action m_actListen;
    		// 侦听异步结果
    		private IAsyncResult m_arListen;
    		// 退出事件
    		private EventWaitHandle m_evCanExit;
    		// 中继目的
    		private IPEndPoint m_epDest;
    		// 安全验证
    		//private SecurityConfirm m_confirm;
    		// 保持对活动连接的引用
    		private List<SocketRelay> m_listSR;
    	}
    你最关心的中继实现:// 包含1对Socket,实现数据传送中继
    	class SocketRelay
    	{
    		public SocketRelay(Socket act, Socket pass)
    		{
    			m_sktActive = act;
    			m_sktPassive = pass;
    		}
     
    		public void Run()
    		{
    			// 把从Passive收到的,发送给Active
    			RecvSend(m_sktPassive, m_sktActive);
    			// 把从Active收到的,发送给Passive
    			RecvSend(m_sktActive, m_sktPassive);
    		}
     
    		public Action<SocketRelay> OnFinished;
     
    		private void RecvSend(Socket sktRecv, Socket sktSend)
    		{
    			RecvPack pack = new RecvPack();
    			pack.sktRecv = sktRecv;
    			pack.sktSend = sktSend;
    			AsyncCallback ac = RecvCallback;
    			sktRecv.BeginReceive(pack.buf, 0, pack.buf.Length, SocketFlags.None, ac, pack);
    		}
     
    		private void RecvCallback(IAsyncResult ar)
    		{
    			try
    			{
    				// 1.接收
    				RecvPack pack = (RecvPack)ar.AsyncState;
    				int nRecv = pack.sktRecv.EndReceive(ar);
    				if (nRecv > 0)
    				{
    					// 2.复制
    					RecvPack packSend = new RecvPack();
    					packSend.sktSend = pack.sktSend;
    					Array.Copy(pack.buf, packSend.buf, nRecv);
    					// 3.发送
    					AsyncCallback ac = SendCallback;
    					pack.sktSend.BeginSend(packSend.buf, 0, nRecv, SocketFlags.None, ac, packSend);
    					// 4.再接收
    					AsyncCallback acRecv = RecvCallback;
    					pack.sktRecv.BeginReceive(pack.buf, 0, pack.buf.Length, SocketFlags.None, acRecv, pack);
    				}
    				else
    				{
    					// 5.关闭连接
    					pack.sktSend.Shutdown(SocketShutdown.Both);
    					pack.sktSend.Close();
    					pack.sktRecv.Shutdown(SocketShutdown.Both);
    					pack.sktRecv.Close();
    					if (OnFinished != null) OnFinished(this);
    				}
    			}
    			catch (SocketException)
    			{
    				// Cancelled 对端关闭了连接
    				if (OnFinished != null) OnFinished(this);
    			}
    			catch (ObjectDisposedException)
    			{
    				// Cancelled
    				if (OnFinished != null) OnFinished(this);
    			}
    		}
     
    		private void SendCallback(IAsyncResult ar)
    		{
    			try
    			{
    				RecvPack pack = (RecvPack)ar.AsyncState;
    				int nSent = pack.sktSend.EndSend(ar);
    			}
    			catch (SocketException)
    			{
    				// Cancelled 对端关闭了连接
    				if (OnFinished != null) OnFinished(this);
    			}
    			catch (ObjectDisposedException)
    			{
    				// Cancelled
    				if (OnFinished != null) OnFinished(this);
    			}
    		}
     
    		// 主动端,即主动发起连接的一端
    		private Socket m_sktActive;
    		// 被动端
    		private Socket m_sktPassive;
    	}
     
    	class RecvPack
    	{
    		public RecvPack()
    		{
    			buf = new byte[1024 * 128];	// 128k
    		}
     
    		public Socket sktRecv;
    		public Socket sktSend;
    		public byte[] buf;
    	}
    

     


    2011年4月28日 8:03

全部回复

  • 这个问题太有难度了。楼主现在做到哪一步了?

    别告诉说只有这个想法,什么代码都没写啊。

    个人建议: 这玩意都是经验累积的。估计在这个地方有牛人,但是贡献代码的可能性。。。

    很期待有人给代码和相关资料。不过还是建议先一步一步的来。

     



    找不到下手的地方 求思路的(我也不是伸手党,但是有这个想法 但是不知道应该用什么技术实现) 没有代码也无所谓  给点提示

    我目前不知道如何连接两个端口转发原始数据,如果这点想不通就没法开始写代码.本人技术确实很菜,做个聊天室没问题,没做过高级的TCP/IP开发.对此一点思路都没有


    楼上可能没看清我的最后一句话,主要是给思路,如果最佳。。  

    “这个程序应该用什么技术做如果能提供一下关键代码/资料最佳”


    • 已编辑 SummerYa 2011年4月28日 3:02 补充内容
    2011年4月28日 2:52
  • 国内类似功能的就是Oray开发的向日葵。

    它里面有个功能叫“远程应用”:能够将远程主机的端口转发到本地主机

     

    这里我将它简化了,不需要涉及P2P打洞之类的,只需要将一个端口映射为另外一个端口即可 

    2011年4月28日 3:08
  • Oray不是花生壳吗?
    2011年4月28日 3:15
  • Oray不是花生壳吗?

    是的

    花生壳是他的一个产品,后来又推出了向日葵,这个是一个能够P2P打洞,实现内网远程控制的管理工具。

    这个功能的需求就是来源向日葵中的远程应用功能(远程端口映射到本地计算机)


    • 已编辑 SummerYa 2011年4月28日 3:29 打错字
    2011年4月28日 3:28
  •  

    这是测试代码,目的是把程序运行所在机器的89号端口中继到202.103.11.22的80端口上:
    
    class Program
    	{
    		static void Main(string[] args)
    		{
    			Console.WriteLine("start : start test");
    			Console.WriteLine("stop : stop test");
    			Console.WriteLine("quit : quit this program");
    
    			RelayListener relay = new RelayListener();
    			relay.Port = 89;
    			relay.DestIP = IPAddress.Parse("202.103.11.22");
    			relay.DestPort = 80;
    			relay.AddAllowIP("127.0.0.1");
    
    			string strRead;
    			do
    			{
    				Console.Write(">");
    				strRead = Console.ReadLine();
    
    				if (strRead == "start")
    				{
    					relay.Start();
    					Console.WriteLine("Start at port {0} -> {1}:{2}", relay.Port, relay.DestIP, relay.DestPort);
    				}
    				else if (strRead == "stop")
    				{
    					relay.Stop();
    					Console.WriteLine("Listener has stopped.");
    				}
    
    			} while (strRead != "quit");
    		}
    	}
    下面是中继监听器的实现:
    public class RelayListener
    	{
    		public RelayListener()
    		{
    			m_evCanExit = new EventWaitHandle(false, EventResetMode.ManualReset);
    			m_actListen = Listen;
    			m_epDest = new IPEndPoint(IPAddress.None, 0);
    			//m_confirm = new SecurityConfirm();
    			m_listSR = new List<SocketRelay>();
    		}
     
    		// 中继侦听端口
    		public int Port { get; set; }
     
    		// 中继目标IP
    		public IPAddress DestIP
    		{
    			get { return m_epDest.Address; }
    			set { m_epDest.Address = value; }
    		}
     
    		// 中继目标端口
    		public int DestPort
    		{
    			get { return m_epDest.Port; }
    			set { m_epDest.Port = value; }
    		}
     
    		public void AddAllowIP(string strIP)
    		{
    			//m_confirm.AddAllowIP(strIP);
    		}
     
    		public void Start()
    		{
    			lock (m_actListen)
    			{
    				// 已存在一个监听,避免重复开启
    				if ((m_arListen != null) && (!m_arListen.IsCompleted)) return;
    				m_evCanExit.Reset();
    				m_arListen = m_actListen.BeginInvoke(null, null);
    			}
    		}
     
    		public void Stop()
    		{
    			lock (m_actListen)
    			{
    				// 没有活动的监听
    				if (m_arListen == null || m_arListen.IsCompleted) return;
    				m_evCanExit.Set();
    				m_actListen.EndInvoke(m_arListen);
    				lock(m_listSR) m_listSR.Clear();
    			}
    		}
     
    		private void Listen()
    		{
    			EventWaitHandle evAccept = new EventWaitHandle(false, EventResetMode.ManualReset);
     
    			// IPv4 TCP
    			using (Socket socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
    			{
    				IPEndPoint ep = new IPEndPoint(IPAddress.Any, Port);
    				socketListener.Bind(ep);
    				socketListener.Listen(5);
     
    				WaitHandle[] waits = new WaitHandle[]
    				{
    					m_evCanExit,
    					evAccept
    				};
     
    				int nWait;	// 等待结果
    				do
    				{
    					evAccept.Reset();
    					AsyncCallback ac = AcceptCallback;
    					Tuple<Socket, EventWaitHandle> state = new Tuple<Socket, EventWaitHandle>(socketListener, evAccept);
    					socketListener.BeginAccept(ac, state);
    					nWait = WaitHandle.WaitAny(waits);
    				}
    				while (nWait != 0);
     
    				socketListener.Close();
    			}
    		}
     
    		private void AcceptCallback(IAsyncResult ar)
    		{
    			Socket sktActive = null;
    			try
    			{
    				var state = (Tuple<Socket, EventWaitHandle>)ar.AsyncState;
    				state.Item2.Set();
    				sktActive = state.Item1.EndAccept(ar);
    			}
    			catch (ObjectDisposedException)
    			{
    				// Accept has been cancelled.
    				return;
    			}
     
    			try
    			{
    				// 安全验证
    				//if (!m_confirm.Confirm(sktActive))
    				//{
    				//	sktActive.Close();
    				//	return;
    				//}
     
    				Socket sktPassive = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    				sktPassive.Connect(m_epDest);
     
    				SocketRelay relay = new SocketRelay(sktActive, sktPassive);
    				relay.OnFinished += OnSocketRelayFinished;
    				relay.Run();
    				lock(m_listSR) m_listSR.Add(relay);
    			}
    			catch (SocketException ex)
    			{
    				string strbuf = String.Format("{0}({1})", ex.Message, ex.ErrorCode);
    				byte[] buf = Encoding.Default.GetBytes(strbuf);
    				sktActive.Send(buf);
     
    				sktActive.Shutdown(SocketShutdown.Both);
    				sktActive.Close();
    			}
    		}
     
    		private void OnSocketRelayFinished(SocketRelay item)
    		{
    			lock (m_listSR)
    			{
    				if(m_listSR.Contains(item))
    					m_listSR.Remove(item);
    			}
    		}
     
    		// 侦听Action
    		private Action m_actListen;
    		// 侦听异步结果
    		private IAsyncResult m_arListen;
    		// 退出事件
    		private EventWaitHandle m_evCanExit;
    		// 中继目的
    		private IPEndPoint m_epDest;
    		// 安全验证
    		//private SecurityConfirm m_confirm;
    		// 保持对活动连接的引用
    		private List<SocketRelay> m_listSR;
    	}
    你最关心的中继实现:// 包含1对Socket,实现数据传送中继
    	class SocketRelay
    	{
    		public SocketRelay(Socket act, Socket pass)
    		{
    			m_sktActive = act;
    			m_sktPassive = pass;
    		}
     
    		public void Run()
    		{
    			// 把从Passive收到的,发送给Active
    			RecvSend(m_sktPassive, m_sktActive);
    			// 把从Active收到的,发送给Passive
    			RecvSend(m_sktActive, m_sktPassive);
    		}
     
    		public Action<SocketRelay> OnFinished;
     
    		private void RecvSend(Socket sktRecv, Socket sktSend)
    		{
    			RecvPack pack = new RecvPack();
    			pack.sktRecv = sktRecv;
    			pack.sktSend = sktSend;
    			AsyncCallback ac = RecvCallback;
    			sktRecv.BeginReceive(pack.buf, 0, pack.buf.Length, SocketFlags.None, ac, pack);
    		}
     
    		private void RecvCallback(IAsyncResult ar)
    		{
    			try
    			{
    				// 1.接收
    				RecvPack pack = (RecvPack)ar.AsyncState;
    				int nRecv = pack.sktRecv.EndReceive(ar);
    				if (nRecv > 0)
    				{
    					// 2.复制
    					RecvPack packSend = new RecvPack();
    					packSend.sktSend = pack.sktSend;
    					Array.Copy(pack.buf, packSend.buf, nRecv);
    					// 3.发送
    					AsyncCallback ac = SendCallback;
    					pack.sktSend.BeginSend(packSend.buf, 0, nRecv, SocketFlags.None, ac, packSend);
    					// 4.再接收
    					AsyncCallback acRecv = RecvCallback;
    					pack.sktRecv.BeginReceive(pack.buf, 0, pack.buf.Length, SocketFlags.None, acRecv, pack);
    				}
    				else
    				{
    					// 5.关闭连接
    					pack.sktSend.Shutdown(SocketShutdown.Both);
    					pack.sktSend.Close();
    					pack.sktRecv.Shutdown(SocketShutdown.Both);
    					pack.sktRecv.Close();
    					if (OnFinished != null) OnFinished(this);
    				}
    			}
    			catch (SocketException)
    			{
    				// Cancelled 对端关闭了连接
    				if (OnFinished != null) OnFinished(this);
    			}
    			catch (ObjectDisposedException)
    			{
    				// Cancelled
    				if (OnFinished != null) OnFinished(this);
    			}
    		}
     
    		private void SendCallback(IAsyncResult ar)
    		{
    			try
    			{
    				RecvPack pack = (RecvPack)ar.AsyncState;
    				int nSent = pack.sktSend.EndSend(ar);
    			}
    			catch (SocketException)
    			{
    				// Cancelled 对端关闭了连接
    				if (OnFinished != null) OnFinished(this);
    			}
    			catch (ObjectDisposedException)
    			{
    				// Cancelled
    				if (OnFinished != null) OnFinished(this);
    			}
    		}
     
    		// 主动端,即主动发起连接的一端
    		private Socket m_sktActive;
    		// 被动端
    		private Socket m_sktPassive;
    	}
     
    	class RecvPack
    	{
    		public RecvPack()
    		{
    			buf = new byte[1024 * 128];	// 128k
    		}
     
    		public Socket sktRecv;
    		public Socket sktSend;
    		public byte[] buf;
    	}
    

     


    2011年4月28日 8:03