簡體   English   中英

將 python 2 代碼轉換為 python 3

[英]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)

其中arg1arg2等來自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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM