Python中测试Socket连接

35

这个问题将扩展至:Python中打开套接字的最佳方法
在打开套接字时,如何测试以查看是否已建立连接,并且它没有超时或通常失败。

编辑: 我尝试了这个:

try:
    s.connect((address, '80'))
except:
    alert('failed' + address, 'down')

但是即使连接应该正常工作,警报函数也会被调用。


在 except 子句中,您应始终使用 traceback 模块中的 print_exc()!这将指示意外错误。 - Alex
4个回答

47

看起来你捕获的不是你想要捕获的异常 :)

如果s是一个socket.socket()对象,那么调用.connect的正确方式应该是:

import socket
s = socket.socket()
address = '127.0.0.1'
port = 80  # port number is a number, not string
try:
    s.connect((address, port)) 
    # originally, it was 
    # except Exception, e: 
    # but this syntax is not supported anymore. 
except Exception as e: 
    print("something's wrong with %s:%d. Exception is %s" % (address, port, e))
finally:
    s.close()

在try-except循环中,尽量确切地了解所捕获的异常类型。

您可以检查socket模块中哪些异常类型表示什么样的错误(超时,无法解析地址等),并为每种类型的错误编写单独的except语句 - 这样您就可以根据不同的问题做出不同的反应。


2
这似乎不起作用,即使如此,警报函数也没有被调用。 - UnkwnTech
1
尝试将 s.connect 移出 try 块。你会得到什么错误? - kender
在测试套接字是否打开后,不要忘记关闭它。 :) - marathon
// ,另外,您认为这个Python示例在Python 3.5中是否有效? - Nathan Basanese
@NathanBasanese 我用s作为OP在问题中使用了这个变量名 :) - kender
显示剩余2条评论

11
您可以使用函数connect_ex。它不会抛出异常,而是返回一个C风格的整数值(在C语言中称为errno):
s =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = s.connect_ex((host, port))
s.close()
if result:
    print "problem with socket!"
else:
    print "everything it's ok!"

3
如果 result > 0,您将得到失败的 errno 值。然后您可以像这样做:print errno.errorcode[result],以获取有关失败的更有用提示。 - Jens
无论连接是正常还是断开,connect_ex() 总是返回“0”。这对我没有用。 - Coliban

6

您应该真正发布:

  1. 您的示例的完整源代码
  2. 实际结果,而不是摘要

这是我的代码,它可以工作:

import socket, sys

def alert(msg):
    print >>sys.stderr, msg
    sys.exit(1)

(family, socktype, proto, garbage, address) = \
         socket.getaddrinfo("::1", "http")[0] # Use only the first tuple
s = socket.socket(family, socktype, proto)

try:
    s.connect(address) 
except Exception, e:
    alert("Something's wrong with %s. Exception type is %s" % (address, e))

当服务器正在监听时,我什么也不会收到(这是正常的),当它没有监听时,我会收到预期的消息:

Something's wrong with ('::1', 80, 0, 0). Exception type is (111, 'Connection refused')

1
// 那个(family, socktype, proto, garbage, address) = \赋值的位是如何工作的?顺便说一句,回答很扎实。 - Nathan Basanese
一个主机名可能有多个IP地址 - 应该循环遍历getaddrinfo的所有结果。但是,应该使用协议ID调用它以跳过UDP和类似的条目:socket.getaddrinfo(address, port, 0, 0, socket.IPPROTO_TCP) - Mikhail T.

2
12年后,对于任何遇到类似问题的人都可以参考此解决方案。
try:
    s.connect((address, '80'))
except:
    alert('failed' + address, 'down')

无法工作是因为端口“80”是字符串。您的端口需要是整数。

try:
    s.connect((address, 80))

这应该可以正常工作。 不确定为什么即使是最佳答案也没有看到这一点。


12年 == 使用上下文管理器比使用TryExcept更好吗? - rustyMagnet

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