[英]converting python 2 code to python 3
我正在尝试将以下用 python 2 编写的代码转换为 python 3。此 python 代码执行 TCP 端口转发。 它来自这个页面: http : //code.activestate.com/recipes/483730-port-forwarding/
import socket
import sys
import thread
def main(setup, error):
sys.stderr = file(error, 'a')
for settings in parse(setup):
thread.start_new_thread(server, settings)
lock = thread.allocate_lock()
lock.acquire()
lock.acquire()
def parse(setup):
settings = list()
for line in file(setup):
parts = line.split()
settings.append((parts[0], int(parts[1]), int(parts[2])))
return settings
def server(*settings):
try:
dock_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
dock_socket.bind(('', settings[2]))
dock_socket.listen(5)
while True:
client_socket = dock_socket.accept()[0]
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.connect((settings[0], settings[1]))
thread.start_new_thread(forward, (client_socket, server_socket))
thread.start_new_thread(forward, (server_socket, client_socket))
finally:
thread.start_new_thread(server, settings)
def forward(source, destination):
string = ' '
while string:
string = source.recv(1024)
if string:
destination.sendall(string)
else:
source.shutdown(socket.SHUT_RD)
destination.shutdown(socket.SHUT_WR)
if __name__ == '__main__':
main('proxy.ini', 'error.log')
这是我所拥有的:
import socket
import sys
import threading
import time
def main(setup, error):
# open file for error messages
sys.stderr = open(error, 'a')
# read settings for port forwarding
threads = []
for settings in parse(setup):
#thread.start_new_thread(server, settings)
t = threading.Thread(target=server, args=(settings))
t.start()
threads.append(t)
for t in threads:
t.join()
# wait for <ctrl-c>
while True:
time.sleep(60)
def parse(setup):
settings = list()
file = open(setup)
for line in iter(file):
parts = line.split()
settings.append((int(parts[0]), parts[1], int(parts[2])))
return settings
def server(*settings):
try:
dock_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
dock_socket.bind(('', settings[0]))
dock_socket.listen(5)
while True:
client_socket = dock_socket.accept()[0]
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.connect((settings[1], settings[2]))
Thread1 = threading.Thread(target=forward, args=(client_socket, server_socket))
Thread1.start()
Thread2 = threading.Thread(target=forward, args=(server_socket, client_socket))
Thread2.start()
finally:
thread = threading.Thread(targer=server, args=settings)
thread.start()
def forward(source, destination):
string = ' '
while string:
string = source.recv(1024)
if string:
destination.sendall(string)
else:
source.shutdown(socket.SHUT_RD)
destination.shutdown(socket.SHUT_WR)
if __name__ == '__main__':
main('port-forward.config', 'error.log')
python 3 版本似乎确实有效。 但我不能完全确定它是否写得正确。 我不清楚代码的线程部分。 python 2 版本使用线程模块,而python 3 版本使用线程模块。 查看python 2版本,它在主函数中使用了锁。 我需要在 python 3 版本中使用锁吗? 另一个问题是,我应该在 python 3 代码的服务器函数中加入两个线程(线程 1 和线程 2)吗?
无论 python 版本如何,我的另一个问题是服务器函数的参数。 我知道“设置”变量是指一个列表。 为什么在“设置”参数之前需要一个星号? 我确实在 python 文档https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists 中查看了以下页面
但我不明白为什么传递没有星号的设置列表不起作用。
我的另一个问题是关于 python 2 代码中的线程锁。 为什么锁被获取两次? 我尝试删除其中一个锁,程序在启动后立即结束。
通过使用命令行工具2to3
将代码转换为 Python 3,您可以节省一些工作,如下所示(来自bash
或 Windows 命令行):
2to3 -w myscript.py
但让我们回答你的实际问题:为什么定义中的明星
def server(*settings):
...
函数thread.start_new_thread
将像这样启动你的server()
函数:
server(arg1, arg2, arg3)
其中arg1
、 arg2
等来自start_new_thread
的第二个参数。 声明def server(*settings)
将这些参数收集回单个列表settings
,您的函数将继续使用该列表。 如果您编写def server(settings)
(无星号),则您的函数被声明为采用一个参数,但将使用多个参数进行调用。
您可以使用 python 3 附带的 2to3 工具作为标准模块。 它为您完成大部分转换。
$2to3 youpythonfile.py
您可以使用 python 3 中的_thread
模块,它与 python 2 中的thread
相同。
您可以使用将 py2 代码转换为 py3 的 futurize 脚本
请参阅: http : //python-future.org/quickstart.html#quick-start-guide安装和http://python-future.org/quickstart.html#to-convert-existing-python-2-code例子
作为您从 Python 手册中引用的代码的作者,我很高兴为 Python 3 重写程序并向您介绍另一个有用的方法。 端口转发是两个食谱中较旧的一个,但它是我第一所大学的大学生使用的完整程序。 Module For Running Simple Proxies是原始代码的改进版本,旨在用于其他程序,而不是单独作为一个完整的程序。 下面的代码采用了端口转发的思想,并将其与运行简单代理模块中的经验教训和此后的经验教训相结合,以提供一个完整且易于阅读的程序供您使用和学习:
import argparse
import re
import select
import socket
import sys
import threading
SETUP_PATTERN = r'^(?P<server_name>\S+)' \
r'\s+(?P<server_port>\d+)' \
r'\s+(?P<proxy_port>\d+)'
SETUP_TYPES = dict(server_name=str, server_port=int, proxy_port=int)
def main():
arguments = parse_arguments()
sys.stderr = open(arguments.error, 'a')
for settings in parse_configuration(arguments.setup):
threading.Thread(target=handle_connections, kwargs=settings).start()
def parse_arguments():
parser = argparse.ArgumentParser(description='Forward TCP traffic.')
parser.add_argument('setup', type=str, help='file with forwarding rules')
parser.add_argument('error', type=str, help='location for error reports')
arguments = parser.parse_args()
return arguments
def parse_configuration(setup):
with open(setup) as file:
for line in file:
match = re.search(SETUP_PATTERN, line)
if match:
yield {key: SETUP_TYPES[key](value)
for key, value in match.groupdict().items()}
def handle_connections(server_name, server_port, proxy_port):
proxy = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proxy.bind((socket.gethostname(), proxy_port))
proxy.listen(5)
while True:
client, address = proxy.accept()
server = socket.create_connection((server_name, server_port))
threading.Thread(target=handle_traffic, args=(client, server)).start()
def handle_traffic(client, server):
pairs, empty = {client: server, server: client}, ()
while pairs:
read, write, error = select.select(pairs.keys(), empty, empty)
for connection in read:
try:
data = connection.recv(1 << 12)
except ConnectionResetError:
data = None
if data:
pairs[connection].sendall(data)
else:
connection.shutdown(socket.SHUT_RD)
pairs.pop(connection).shutdown(socket.SHUT_WR)
client.close()
server.close()
if __name__ == '__main__':
main()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.