简体   繁体   English

将 python 2 代码转换为 python 3

[英]converting python 2 code to python 3

I am trying to convert the following code written in python 2 to python 3. This python code does TCP port forwarding.我正在尝试将以下用 python 2 编写的代码转换为 python 3。此 python 代码执行 TCP 端口转发。 It is from this page: http://code.activestate.com/recipes/483730-port-forwarding/它来自这个页面: 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')

Here is what I have:这是我所拥有的:

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')

The python 3 version does seem to work. python 3 版本似乎确实有效。 But I am not fully certain if it is written correctly.但我不能完全确定它是否写得正确。 I am unclear about the threads portion of the code.我不清楚代码的线程部分。 The python 2 version is using the thread module while the python 3 version is using the threading module. python 2 版本使用线程模块,而python 3 版本使用线程模块。 Looking at the python 2 version, it uses locks in the main function.查看python 2版本,它在主函数中使用了锁。 Do I need to use locks in the python 3 version?我需要在 python 3 版本中使用锁吗? Another question is, should I be joining the two threads (thread 1 and thread 2) in the server function in the python 3 code?另一个问题是,我应该在 python 3 代码的服务器函数中加入两个线程(线程 1 和线程 2)吗?

Another question I have regardless of python version is the argument to the server function.无论 python 版本如何,我的另一个问题是服务器函数的参数。 I understand that the "settings" variable refers to a list.我知道“设置”变量是指一个列表。 Why does there need to be a asterisk preceding the "settings" argument?为什么在“设置”参数之前需要一个星号? I did take a look at the following page in python documentation https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists我确实在 python 文档https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists 中查看了以下页面

But I don't understand why passing the settings list without the asterisk doesn't work.但我不明白为什么传递没有星号的设置列表不起作用。

Another question I have is regarding the thread locks in the python 2 code.我的另一个问题是关于 python 2 代码中的线程锁。 Why is the lock being acquired twice?为什么锁被获取两次? I tried removing one of the locks and the program ends immediately after being started.我尝试删除其中一个锁,程序在启动后立即结束。

You could have saved yourself some work by using the commandline tool 2to3 to convert the code to Python 3, like this (from the bash or Windows command line):通过使用命令行工具2to3将代码转换为 Python 3,您可以节省一些工作,如下所示(来自bash或 Windows 命令行):

2to3 -w myscript.py

But let's answer your actual question: Why the star in the definition但让我们回答你的实际问题:为什么定义中的明星

def server(*settings):
    ...

The function thread.start_new_thread will in effect launch your server() function like this:函数thread.start_new_thread将像这样启动你的server()函数:

server(arg1, arg2, arg3)

where arg1 , arg2 etc. come from the second argument of start_new_thread .其中arg1arg2等来自start_new_thread的第二个参数。 The declaration def server(*settings) collects these arguments back into a single list, settings , which your function goes on to use.声明def server(*settings)将这些参数收集回单个列表settings ,您的函数将继续使用该列表。 If you write def server(settings) (no star), your function is declared to take one argument but will be called with several.如果您编写def server(settings) (无星号),则您的函数被声明为采用一个参数,但将使用多个参数进行调用。

You can use the 2to3 tool that come with python 3 as a standard module.您可以使用 python 3 附带的 2to3 工具作为标准模块。 It does most of the conversion for you.它为您完成大部分转换。

$2to3 youpythonfile.py

You can use the _thread module in python 3 which is identical to thread in python 2.您可以使用 python 3 中的_thread模块,它与 python 2 中的thread相同。

You can use the futurize script which convert your py2 code into py3您可以使用将 py2 代码转换为 py3 的 futurize 脚本

See : http://python-future.org/quickstart.html#quick-start-guide for installation and http://python-future.org/quickstart.html#to-convert-existing-python-2-code for example请参阅: http : //python-future.org/quickstart.html#quick-start-guide安装和http://python-future.org/quickstart.html#to-convert-existing-python-2-code例子

As the author of the code that you referenced from the Python cookbook, it is my pleasure to rewrite the program for Python 3 and introduce you to another useful recipe.作为您从 Python 手册中引用的代码的作者,我很高兴为 Python 3 重写程序并向您介绍另一个有用的方法。 Port Forwarding is the older of the two recipes but was a complete program used as a college student at my first college.端口转发是两个食谱中较旧的一个,但它是我第一所大学的大学生使用的完整程序。 Module For Running Simple Proxies is a improved version of the original code and was designed for use in other programs rather than being a complete program by itself. Module For Running Simple Proxies是原始代码的改进版本,旨在用于其他程序,而不是单独作为一个完整的程序。 The code that follows takes the idea of Port Forwarding and combines it with lessons learned in Module For Running Simple Proxies and lessons learned since then to provide a complete and hopefully easy-to-read program for your use and study:下面的代码采用了端口转发的思想,并将其与运行简单代理模块中的经验教训和此后的经验教训相结合,以提供一个完整且易于阅读的程序供您使用和学习:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM