通过干线库连接的连接数 - 控制器创建2个连接,但关闭控制器只会删除一个连接

时间:2017-01-18 14:52:32

标签: python tcp tor stem

我正在使用词库,我正在Stem Controller类上编写一个瘦包装器。

我有一些问题与实例化控制器时创建的连接数有关,以及控制器关闭时删除的连接数。

这是我到目前为止的代码:

import logging

import sys
import subprocess
from optparse import OptionParser

import stem
from stem.control import Controller

SOCKET_ERROR_CODE = 2
MISSING_PWD_ERROR_CODE = 3
PWD_FAIL_ERROR_CODE = 4
AUTH_FAIL_ERROR_CODE = 5
UNKNOWN_ERROR_CODE = -1


class StemController():
    def __init__(self):
        # Added print statements for debugging - Yes, I know, shell=True is bad
        print(
            "[__init__ start] ",
            str(int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip()))
        )

        # Controller connection and credentials
        self.tor_router_ip = "127.0.0.1"
        self.tor_router_port = 9051
        self.tor_password = "controllportpassword"  # Add yours to test

        #  Create a controller - This might actually fail
        try:
            # Tried both and one at a time, still two connections
            self.controller = Controller.from_port(
                # address=self.tor_router_ip,
                 port=self.tor_router_port
            )
        except stem.SocketError as e:
            logging.info("SocketError when opening controller. Now existing with code %s." % (
                SOCKET_ERROR_CODE
            ))
            sys.exit(SOCKET_ERROR_CODE)
        except Exception as e:
            logging.exception(e)
            sys.exit(UNKNOWN_ERROR_CODE)

        print(
            "[Controller created] ",
            str(int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip()))
        )

        # Authenticate controller - This might fail as well
        try:
            self.controller.authenticate(password=self.tor_password)
        except stem.connection.MissingPassword:
            logging.info(
                "MissingPassword when authenticating controller. Now existing with code %s." % MISSING_PWD_ERROR_CODE
            )
            self.controller.close()
            sys.exit(MISSING_PWD_ERROR_CODE)
        except stem.connection.PasswordAuthFailed:
            logging.info(
                "PasswordAuthFailed when authenticating controller. Now existing with code %s." % PWD_FAIL_ERROR_CODE
            )
            self.controller.close()
            sys.exit(PWD_FAIL_ERROR_CODE)
        except stem.connection.AuthenticationFailure:
            logging.info(
                "AuthenticationFailure when authenticating controller. Now existing with code %s." % AUTH_FAIL_ERROR_CODE
            )
            self.controller.close()
            sys.exit(AUTH_FAIL_ERROR_CODE)
        except Exception as e:
            logging.exception(e)
            self.controller.close()
            sys.exit(UNKNOWN_ERROR_CODE)

        print(
            "[Controller auth] ",
            str(int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip()))
        )

    def __del__(self):
        init_tor_connections = int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip())
        print(
            "\nDeleting and cleaning up controller. Before cleanup there are %s tor connections." % init_tor_connections
        )

        self.controller.close()

        final_tor_connections = int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip())
        print(
            "After deletion of controller. After cleanup there are %s tor connections." % final_tor_connections
        )


import unittest


class TestStemController(unittest.TestCase):
    def setUp(self):
        #  This is a darknet site that is almost always up
        self.up_site = "deepdot35wvmeyd5.onion"

    def test_stem_controller(self):
        # Make sure that the controller opens and closes correctly
        # Count how many connections on port 9051 we have
        pre_stem_controller = int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip())
        print("pre_stem_controller: ", pre_stem_controller)
        test_stem_controller = StemController()
        # Count how many connections on port 9051 we have after initializing the controller
        post_stem_controller = int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip())
        print("post_stem_controller: ", post_stem_controller)
        # We should have one more connection, since we created another once when we initialized the controller
        self.assertEqual(post_stem_controller, pre_stem_controller + 1)
        # Delete the controller
        del test_stem_controller
        # Count how many connections on port 9051 we have after deleting the controller
        post_del_stem_controller = int(subprocess.check_output('netstat -na | grep 9051 | wc -l', shell=True).strip())
        print("post_del_stem_controller: ", post_del_stem_controller)
        # We should have as many as we had in the beginning
        self.assertEqual(post_del_stem_controller, pre_stem_controller)


def suite():
    test_suite = unittest.TestSuite()
    test_suite.addTest(TestStemController('test_stem_controller'))
    return test_suite


if __name__ == '__main__':
    arguments = sys.argv[1:]
    parse = OptionParser("This is the stem controller script script.")
    parse.add_option(
        "-u",
        "--unittests",
        help="Action: Run unittests.",
        default=False,
        action='store_true'
    )

    (options, arguments) = parse.parse_args()

    if options.unittests:
        test_suite = suite()
        unittest.TextTestRunner().run(test_suite)
        logging.info("Unittests done. Now existing.")
        sys.exit()

TL;代码DR:计算端口9051上的连接数,创建控制器,再次计算端口9051上的连接数,并将数字增加1。除了断言连接数减1之外,删除的内容相同。

我使用python3 stem_code.py -u运行我的代码并获取,例如:

pre_stem_controller:  1
[__init__ start]  1
[Controller created]  3
[Controller auth]  3
post_stem_controller:  3
F
Deleting and cleaning up controller. Before cleanup there are 3 tor connections.
After deletion of controller. After cleanup there are 2 tor connections.

======================================================================
FAIL: test_stem_controller (__main__.TestStemController)
----------------------------------------------------------------------
Traceback (most recent call last):
  self.assertEqual(post_stem_controller, pre_stem_controller + 1)
AssertionError: 3 != 2

----------------------------------------------------------------------
Ran 1 test in 0.050s

FAILED (failures=1)

我认为最相关的部分是:

[__init__ start]  1
[Controller created]  3

我的第一个问题是:为什么在这里创建了两个连接?

我已经提出了一个理论,为什么会这样,但我不确定。

很想知道这两个连接是什么,我在实例化控制器后做了这个:

netstat -na | grep 9051

结果如下:

tcp        0      0 127.0.0.1:9051          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:9051          127.0.0.1:40606         ESTABLISHED
tcp        0      0 127.0.0.1:40606         127.0.0.1:9051          ESTABLISHED

所以,我让tor客户端监听端口9051(第一行)和两个连接,一个从tor到stem(9051到40606,第二行),一个从stem到tor(40606到9051,第三行)。

这是双重连接,是为了阻止和阻止创建两个连接的原因吗?

在此之后,我决定采用创建2个连接的事实。所以我将单元测试从+1更改为+2以传递该特定断言。测试继续进行,但未能通过断言初始化前的连接数等于删除后的连接数。

    self.assertEqual(post_del_stem_controller, pre_stem_controller)
AssertionError: 2 != 1

使用与连接相同的程序,我做了netstat -na并执行此操作:

tcp        0      0 127.0.0.1:9051          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:9051          127.0.0.1:40636         TIME_WAIT

连接杆的连接似乎仍然存在。

我认为当我这样做时是正确的 controller.close() 我只关闭干线连接但是干线连接保持活动状态(至少有一段时间, TIME_WAIT州)?

现在,假设到目前为止我是正确的:

  1. 有没有办法迫使tor关闭它的连接侧?

  2. 有没有理由试图强行关闭它的连接? (我的理由是这样的。我知道有一个最大数量的256个连接到客户端。我希望尽可能多的免费)。否则,处于TIME_WAIT状态的连接算作实际连接?例如,如果我有255个ESTABLISHED连接和一个TIME_WAIT,我仍然能够建立另一个与tor的连接吗?

  3. 您认为这是测试我的包装器类的正确方法,还是有更好的方法来确保控制器正确打开和关闭?

  4. 谢谢!

1 个答案:

答案 0 :(得分:1)

  1. 就Tor而言,连接已关闭。也就是说,它已经释放了该连接,并且不再将该客户端视为已连接。当套接字处于TIME_WAIT状态时,套接字已关闭,但操作系统将其保留,以确保没有延迟数据包从旧连接到达,这可能会被来自同一组端口的后续连接所接受(例如40606来自你的例子)。
  2. 您可以缩短操作系统中的TIME_WAIT期限,但它并不能真正解决问题。有关详细信息,请参阅http://www.isi.edu/touch/pubs/infocomm99/infocomm99-web/http://www.linuxbrigade.com/reduce-time_wait-socket-connections/

    1. 没有。关闭与控制器的连接后,Tor会减少已连接客户端的数量,以便将其释放以接受更多。我不担心。

    2. 可能不是。为什么在只能向控制器发出命令并读取响应时,使用netstat来测试连接?

    3. 你看到3个连接的原因是因为首先是9051上的监听套接字,然后当你连接时,netstat会显示同一连接的两端(因为它是本地的)。因此,您可以看到使用端口40636连接 Tor,然后您也(因为它是本地连接)从<来看连接 / em>您的控制客户端也在端口40636上。连接的这两端实际上代表了一个连接。

      因此,只要您连接到本地Tor实例,netstat中的每行连接数就会增加2。

      您可以通过将grep更改为

      来消除输出中的本地客户端连接
      netstat -ano|grep -E ':9051[[:space:]]+[[:digit:]]'
      

      然后,您可以通过以下方式进一步过滤LISTENING连接:

      netstat -ano|grep -E ':9051[[:space:]]+[[:digit:]]'|grep -v 'LISTENING'
      
        

      我认为当我做controller.close()时我是正确的   关闭阀杆连接,但阀杆连接   保持活动状态(至少有一段时间,TIME_WAIT状态)?

      执行controller.close()时,两者都已关闭。 Tor不再将连接视为开放,由于上述原因,它只是被操作系统保留;确保使用相同端口组合的另一个连接不会建立并可能接受来自新连接的先前连接的延迟数据包。它在Tor的眼中不再开放,它已将客户端从其连接列表中删除。

      希望能回答你的问题。