Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于 Limit_Clients 在python3下的bug。 #2

Closed
falseen opened this issue Mar 5, 2017 · 2 comments
Closed

关于 Limit_Clients 在python3下的bug。 #2

falseen opened this issue Mar 5, 2017 · 2 comments
Assignees

Comments

@falseen
Copy link
Owner

falseen commented Mar 5, 2017

# 动态patch类方法
def new_class_method(_class, method_name, new_method):
    method = getattr(_class, method_name)
    info = sys.version_info
    if info[0] >= 3:
        setattr(_class, method_name,
                types.MethodType(lambda *args, **kwds: new_method(method, *args, **kwds), _class))
    else:
        setattr(_class, method_name,
                types.MethodType(lambda *args, **kwds: new_method(method, *args, **kwds), None, _class))

# 自定义 socket 类,可以自定义实例方法或属性。
class new_socket(socket.socket):

    def __init__(self, *args, **kwds):
        super(new_socket, self).__init__(*args, **kwds)


def new_bind(orgin_method, self, *args, **kwds):
    
    # 如果绑定地址是0,那这个 socket 就一定不是和客户端通信的。
    # 此处主要是考虑到shadowsocks服务端在做流量转发的时候会对本地的socket进行绑定。
    if args[0][1] != 0:
        if only_port:
            server_addrs = '*:%s' % args[0][1]
        else:
            server_addrs = '%s:%s' % (args[0][0], args[0][1])
        self._server_addrs = server_addrs
        self._all_client_list.update({server_addrs:{}})
        new_self_method(self, 'recvfrom', new_recvfrom)
    orgin_method(self, *args, **kwds)


new_class_method(socket.socket, 'bind', new_bind)
socket.socket = new_socket

上面的这段代码会把socket的bind方法替换成 new_bind,在python2下运行正常。但是在python3下,new_bind 的 self 参数无法获取到实例本身,反而获取到的是一个 type 类型的 class socket.new_socket 这让我百思不得其解。反复查资料也没得到答案,如果有哪位高手知道的话,烦请告知一下。

@huangy10
Copy link
Contributor

原因其实不复杂,不过我也绕晕了一会儿,问题在于Python2和Python3中的types.MethodType的作用不一样了。在ipython中通过help来列出二者的用法,可以发现是不同的:

# Python 2
Help on class instancemethod in module __builtin__:

class instancemethod(object)
 |  instancemethod(function, instance, class)
 |
 |  Create an instance method object.

# Python 3
class method(object)
 |  method(function, instance)
 |
 |  Create a bound instance method object.

在Python2中,你可以把一个方法作为“实例方法”绑定到一个类的身上,并且之后从该类创建的实例的对应方法,都将是你所指定的这个方法。但是Python3中不同了,如果你将instance指定成一个类,那么Python3会将这个类视为一个实例,为其绑定一个bind方法,那么此时的bind实质上就成了这个类的类方法。所以你在new_bind函数中拿到的self就是类本身了(cls)。

解决这个问题很简单。我创建了一个新的PR,相信你一看就懂了。

@falseen
Copy link
Owner Author

falseen commented Jan 10, 2018

感谢!终于把这个问题给解决了。

@falseen falseen closed this as completed Jan 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants