【问题标题】:converting python 2 code to python 3将 python 2 代码转换为 python 3
【发布时间】:2017-03-17 09:16:17
【问题描述】:

我正在尝试将以下用 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 版本使用 thread 模块,而 python 3 版本使用 threading 模块。查看 python 2 版本,它在 main 函数中使用了锁。我需要在 python 3 版本中使用锁吗?另一个问题是,我应该在 python 3 代码的服务器函数中加入两个线程(线程 1 和线程 2)吗?

无论 python 版本如何,我的另一个问题是服务器函数的参数。我知道“设置”变量是指一个列表。为什么“设置”参数之前需要一个星号?我确实查看了python文档https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists中的以下页面@

但我不明白为什么通过不带星号的设置列表不起作用。

我的另一个问题是关于 python 2 代码中的线程锁。为什么锁被获取两次?我尝试移除其中一个锁,程序在启动后立即结束。

【问题讨论】:

  • 我已经编辑了帖子以添加我的另一个问题。

标签: python multithreading python-2.7 python-3.x sockets


【解决方案1】:

您可以通过使用命令行工具 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)(没有星号),你的函数被声明为接受一个参数,但会被多个参数调用。

【讨论】:

  • 感谢 Alexis 解释加星标的论点。
【解决方案2】:

您可以使用 python 3 附带的 2to3 工具作为标准模块。它会为您完成大部分转换。

$2to3 youpythonfile.py

您可以在 python 3 中使用 _thread 模块,它与 python 2 中的 thread 相同。

【讨论】:

    【解决方案3】:

    您可以使用 futurize 脚本将您的 py2 代码转换为 py3

    请参阅:http://python-future.org/quickstart.html#quick-start-guide 进行安装,http://python-future.org/quickstart.html#to-convert-existing-python-2-code 示例

    【讨论】:

      【解决方案4】:

      作为您从 Python 食谱中引用的代码的作者,我很高兴为 Python 3 重写程序并向您介绍另一个有用的食谱。 Port Forwarding 是两个食谱中较老的一个,但它是我第一所大学作为大学生使用的完整程序。 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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-12
        • 2016-10-19
        • 2023-03-20
        • 1970-01-01
        • 2018-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多