Python套接字连接异常

21

我正在进行套接字连接,想要改进异常处理,但是卡住了。每当我使用无效的参数调用socket.connect(server_address)时,程序会停止运行,但似乎没有引发异常。这是我的代码:

import socket
import sys
import struct
class ARToolkit():
    
    def __init__(self):
        self.x = 0
        self.y = 0
        self.z = 0
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.logging = False
    
    def connect(self,server_address):
        try:
            self.sock.connect(server_address)
        except socket.error, msg:
            print "Couldnt connect with the socket-server: %s\n terminating program" % msg
            sys.exit(1)
    
    def initiate(self):
        self.sock.send("start_logging")
    
    def log(self):
        self.logging  = True  
        buf = self.sock.recv(6000)
        if len(buf)>0:
            nbuf = buf[len(buf)-12:len(buf)]
            self.x, self.y, self.z = struct.unpack("<iii", nbuf) 
    
    def stop_logging(self):
        print "Stopping logging"
        self.logging = False
        self.sock.close()
            

这个类看起来可能有些奇怪,但它用于从运行ARToolKit的另一台计算机接收坐标。无论如何,问题出现在函数connect()中:

def connect(self,server_address):
    try:
        self.sock.connect(server_address)
    except socket.error, msg:
        print "Couldnt connect with the socket-server: %s\n terminating program" % msg
        sys.exit(1)

如果我使用随机 IP 地址和端口号调用该函数,整个程序将停留在以下行:

self.sock.connect(server_address)

我阅读的文档说明,在出现错误时它会抛出一个socket.error异常。我也尝试过只使用:

except Exception, msg:

如果我没记错的话,这个代码可以捕获所有异常,但它并没有返回任何结果。如果有人能帮忙解决问题,我将不胜感激。另外,当出现意外异常时,使用sys.exit退出程序是否可以接受?

谢谢!


你如何启动你的程序?你确定你的打印输出不会进入 /dev/null 或其他地方吗?此外,一些异常继承自 BaseException,所以如果你真的很绝望,也可以尝试捕获它(包括 sys.exit 和 keyboard interrupt)。 - user3012759
2个回答

25
如果您选择了一个随机但有效的 IP 地址和端口,socket.connect() 将尝试连接到该端点。默认情况下,如果没有为套接字设置显式超时时间,则在进行连接时它将会阻塞并最终超时,引发异常 socket.error: [Errno 110] Connection timed out
在我的计算机上,缺省超时时间是120秒。也许您等待 socket.connect() 返回(或超时)的时间不够长?
您可以尝试像这样减少超时时间:
import socket

s = socket.socket()
s.settimeout(5)   # 5 seconds
try:
    s.connect(('123.123.123.123', 12345))         # "random" IP address and port
except socket.error, exc:
    print "Caught exception socket.error : %s" % exc

请注意,如果为套接字明确设置了超时时间,那么产生的异常将是socket.timeout,它是派生自socket.error,因此将被上述except语句捕获。


1
谢谢兄弟!这就是问题所在,我手动终止了程序而不是等待超时。 - erling
如果超时设置为“None”,那么您是说在120秒(或其他默认值)后仍然会出现超时异常吗?我该如何获取/设置此默认值? - Itamar Katz
1
@ItamarKatz:那个超时是系统定义的。在Linux(和其他Unix变体)中,它是通过建立连接的重试次数间接控制的 - 实际上是尝试获取SYN数据包响应的次数。您可以使用cat /proc/sys/net/ipv4/tcp_syn_retries命令查看设置。您还可以通过修改该特殊文件来更改它。通常使用指数退避算法发送重试,即增加重试之间的时间间隔,例如3、7、15、31秒。我的Linux系统将tcp_syn_retries设置为5,这大约需要120秒。 - mhawke
1
@ItamarKatz:更改该设置会影响系统上的所有进程,因此我建议不要这样做。如果您想设置超时,请使用socket.settimeout()。如果您想要比操作系统允许的超时时间更长的超时时间,则需要通过在Python中执行自己的重试来处理。 - mhawke
如果我只写Exception而不是socket.error,那么except子句会捕获任何类型的异常吗? - y_159
显示剩余3条评论

9
你最后一个通用异常的问题在于冒号的放置位置。它需要放在整个异常之后,而不是放在except语句之后。因此,如果要捕获所有异常,你需要这样做:
except Exception,msg:

然而,从Python 2.6+开始,您应该使用as语句而不是逗号,就像这样:
except Exception as msg:

我成功地运行了代码(请注意,您需要在connect方法中添加一个元组)。如果您想专门捕获套接字错误,则需要捕获socket.error类。就像您已经写的那样:

except socket.error as msg:

如果您想确保元组的输入,请添加另一个异常循环:
except socket.error as msg:
    print "Socket Error: %s" % msg
except TypeError as msg:
    print "Type Error: %s" % msg

2
谢谢您的建议,但是在更改超时时间后,即使我没有使用“as”,我现在也能捕获异常。冒号错位是一个笔误。 - erling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接