代码之家  ›  专栏  ›  技术社区  ›  bstpierre Edgar Aviles

当您从python对象抛出异常时,它会发生什么情况

  •  2
  • bstpierre Edgar Aviles  · 技术社区  · 15 年前

    当它“卡住”时,netstat显示两个连接到端口的套接字。服务器正在等待来自第一个套接字的输入,但是它还没有处理新的套接字。

    我在一个虚拟服务器上运行此操作,该虚拟服务器对每一条传入线路都回复“error\n”。

    Mark Rushakoff's answer below

    import socket
    
    class MyException(Exception):
        pass
    
    class MyClient(object):
    
        def __init__(self, port):
            self.sock = socket.create_connection(('localhost', port))
            self.sockfile = self.sock.makefile()
    
        def do_stuff(self):
            self._send("do_stuff\n")
            response = self._receive()
            if response != "ok\n":
                raise MyException()
            return response
    
        def _send(self, cmd):
            self.sockfile.write(cmd)
            self.sockfile.flush()
    
        def _receive(self):
            return self.sockfile.readline()
    
    def connect():
        c = MyClient(9989)
        # On the second iteration, do_stuff() tries to send data and
        # hangs indefinitely.
        print c.do_stuff()
    
    if __name__ == '__main__':
        for _ in xrange(3):
            try:
                connect()
            except MyException, e:
                print 'Caught:', e
                # This would be the workaround if I had access to the
                # MyClient object:
                #c.sock.close()
                #c.sockfile.close()
    

    编辑:以下是(丑陋的)服务器代码:

    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    s.bind(('localhost', 9989))
    s.listen(5)
    (c,a) = s.accept()
    f = c.makefile()
    print f.readline()
    f.write('error\n')
    f.flush()
    (c2,a) = s.accept()
    f = c.makefile()
    print f.readline()
    s.close()
    
    4 回复  |  直到 7 年前
        1
  •  5
  •   Mark Rushakoff    15 年前

    这是垃圾收集的产物。即使对象是 ,不一定 因此 摧毁

    您可能可以通过更改 connect

    def connect():
        try:
            c = MyClient(9989)
            # On the second iteration, do_stuff() tries to send data and
            # hangs indefinitely.
            print c.do_stuff()
        finally:
            c.sock.close()
            c.sockfile.close()
    

    或者,您可以定义 __enter__ __exit__ 对于 MyClient ,然后呢 a with statement

    def connect():
        with MyClient(9989) as c:
            print c.do_stuff()
    

    这实际上与最后一次尝试相同。

        2
  •  1
  •   u0b34a0f6ae    15 年前

    我认为您应该提供一个MyClient.close()方法,并像这样编写connect():

    def connect():
        try:
            c = MyClient(9989)
            print c.do_stuff()
        finally:
            c.close()
    

    这与类似文件的对象(以及with语句)完全相似

        3
  •  0
  •   whatnick    15 年前

    通过将相关对象设置为“无”,可以将垃圾收集器标记为清理。

        4
  •  0
  •   bstpierre Edgar Aviles    15 年前

    import socket
    
    class MyException(Exception):
        pass
    
    class MyClient(object):
    
        def __init__(self, port):
            self.sock = socket.create_connection(('localhost', port))
            self.sockfile = self.sock.makefile()
    
        def close(self):
            self.sock.close()
            self.sockfile.close()
    
        def do_stuff(self):
            self._send("do_stuff\n")
            response = self._receive()
            if response != "ok\n":
                raise MyException()
            return response
    
        def _send(self, cmd):
            self.sockfile.write(cmd)
            self.sockfile.flush()
    
        def _receive(self):
            return self.sockfile.readline()
    
    def connect():
        try:
            c = MyClient(9989)
            print c.do_stuff()
        except MyException:
            print 'Caught MyException'
        finally:
            c.close()
    
    if __name__ == '__main__':
        for _ in xrange(2):
            connect()