【任务】
需要将某个网络端口转发到另一个主机(forwarding),但可能会是不同的端口(redirecting)。
【解决方案】
两个使用threading和socket模块的类就能完成我们需要的端口转发和重定向。
<code>#encoding=utf8</code>
<code>#author: walker摘自《Python Cookbook(2rd)》</code>
<code>#date: 2015-06-11</code>
<code>#function: 网络端口的转发和重定向(适用于python2/python3)</code>
<code>import</code> <code>sys, socket, time, threading</code>
<code>LOGGING </code><code>=</code> <code>True</code>
<code>loglock </code><code>=</code> <code>threading.Lock()</code>
<code>#打印日志到标准输出</code>
<code>def</code> <code>log(s, </code><code>*</code><code>a):</code>
<code> </code><code>if</code> <code>LOGGING:</code>
<code> </code><code>loglock.acquire()</code>
<code> </code><code>try</code><code>:</code>
<code> </code><code>print</code><code>(</code><code>'%s:%s'</code> <code>%</code> <code>(time.ctime(), (s </code><code>%</code> <code>a)))</code>
<code> </code><code>sys.stdout.flush()</code>
<code> </code><code>finally</code><code>:</code>
<code> </code><code>loglock.release()</code>
<code> </code>
<code>class</code> <code>PipeThread(threading.Thread):</code>
<code> </code><code>pipes </code><code>=</code> <code>[] </code><code>#静态成员变量,存储通讯的线程编号</code>
<code> </code><code>pipeslock </code><code>=</code> <code>threading.Lock()</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, source, sink):</code>
<code> </code><code>#Thread.__init__(self) #python2.2之前版本适用</code>
<code> </code><code>super</code><code>(PipeThread, </code><code>self</code><code>).__init__()</code>
<code> </code><code>self</code><code>.source </code><code>=</code> <code>source</code>
<code> </code><code>self</code><code>.sink </code><code>=</code> <code>sink</code>
<code> </code><code>log(</code><code>'Creating new pipe thread %s (%s -> %s)'</code><code>, </code>
<code> </code><code>self</code><code>, source.getpeername(), sink.getpeername())</code>
<code> </code><code>self</code><code>.pipeslock.acquire()</code>
<code> </code><code>self</code><code>.pipes.append(</code><code>self</code><code>)</code>
<code> </code><code>self</code><code>.pipeslock.release()</code>
<code> </code><code>pipes_now </code><code>=</code> <code>len</code><code>(</code><code>self</code><code>.pipes)</code>
<code> </code><code>log(</code><code>'%s pipes now active'</code><code>, pipes_now)</code>
<code> </code><code>def</code> <code>run(</code><code>self</code><code>):</code>
<code> </code><code>while</code> <code>True</code><code>:</code>
<code> </code><code>try</code><code>:</code>
<code> </code><code>data </code><code>=</code> <code>self</code><code>.source.recv(</code><code>1024</code><code>)</code>
<code> </code><code>if</code> <code>not</code> <code>data:</code>
<code> </code><code>break</code>
<code> </code><code>self</code><code>.sink.send(data)</code>
<code> </code><code>except</code><code>:</code>
<code> </code><code>break</code>
<code> </code><code>log(</code><code>'%s terminating'</code><code>, </code><code>self</code><code>) </code>
<code> </code><code>self</code><code>.pipes.remove(</code><code>self</code><code>)</code>
<code> </code><code>pipes_left </code><code>=</code> <code>len</code><code>(</code><code>self</code><code>.pipes)</code>
<code> </code><code>log(</code><code>'%s pipes still active'</code><code>, pipes_left)</code>
<code> </code>
<code>class</code> <code>Pinhole(threading.Thread):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, port, newhost, newport):</code>
<code> </code><code>super</code><code>(Pinhole, </code><code>self</code><code>).__init__()</code>
<code> </code><code>log(</code><code>'Redirecting: localhost: %s->%s:%s'</code><code>, port, newhost, newport)</code>
<code> </code><code>self</code><code>.newhost </code><code>=</code> <code>newhost</code>
<code> </code><code>self</code><code>.newport </code><code>=</code> <code>newport</code>
<code> </code><code>self</code><code>.sock </code><code>=</code> <code>socket.socket(socket.AF_INET, socket.SOCK_STREAM)</code>
<code> </code><code>self</code><code>.sock.bind(('', port))</code>
<code> </code><code>self</code><code>.sock.listen(</code><code>5</code><code>) </code><code>#参数为timeout,单位为秒</code>
<code> </code><code>newsock, address </code><code>=</code> <code>self</code><code>.sock.accept()</code>
<code> </code><code>log(</code><code>'Creating new session for %s:%s'</code><code>, </code><code>*</code><code>address)</code>
<code> </code><code>fwd </code><code>=</code> <code>socket.socket(socket.AF_INET, socket.SOCK_STREAM)</code>
<code> </code><code>fwd.connect((</code><code>self</code><code>.newhost, </code><code>self</code><code>.newport))</code>
<code> </code><code>PipeThread(newsock, fwd).start() </code><code>#正向传送</code>
<code> </code><code>PipeThread(fwd, newsock).start() </code><code>#逆向传送</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>
<code> </code><code>print</code><code>(</code><code>'Starting Pinhole port fowarder/redirector'</code><code>)</code>
<code> </code>
<code> </code><code>try</code><code>:</code>
<code> </code><code>port </code><code>=</code> <code>int</code><code>(sys.argv[</code><code>1</code><code>])</code>
<code> </code><code>newhost </code><code>=</code> <code>sys.argv[</code><code>2</code><code>]</code>
<code> </code><code>newport </code><code>=</code> <code>int</code><code>(sys.argv[</code><code>3</code><code>])</code>
<code> </code><code>except</code> <code>IndexError:</code>
<code> </code><code>newport </code><code>=</code> <code>port</code>
<code> </code><code>except</code> <code>(ValueError, IndexError):</code>
<code> </code><code>print</code><code>(</code><code>'Usage: %s port newhost [newport]'</code> <code>%</code> <code>sys.argv[</code><code>0</code><code>])</code>
<code> </code><code>sys.exit(</code><code>1</code><code>)</code>
<code> </code><code>#sys.stdout = open('pinhole.log', 'w') #将日志写入文件</code>
<code> </code><code>Pinhole(port, newhost, newport).start()</code>
【讨论】
当你在管理一个网络时,即使是一个很小的网络,端口转发和重定向的功能有时也能给你很大的帮助。一些不在你的控制之下的应用或者服务可能是以硬连接的方式接入到某个特定的服务器的地址或端口。通过插入转发和重定向,你就能将对应用的连接请求发送到其他更合适的主机或端口上。
本文转自walker snapshot博客51CTO博客,原文链接http://blog.51cto.com/walkerqt/1660749如需转载请自行联系原作者
RQSLT