Python for 循环变慢并最终挂起

6 投票
4 回答
2129 浏览
提问于 2025-04-16 16:08

我刚接触Python(就半个小时之前)并尝试写一个简单的脚本,用来列出SMTP服务器上的用户。

用户文件就是一个简单的列表,每行一个用户名。

脚本运行得很好,但每次循环的时候速度都会变慢,直到大约第14次循环时,似乎完全卡住了。没有任何错误提示,我只能按^c来停止。

有没有人能帮我解释一下这个问题呢?

谢谢,
汤姆

#!/usr/bin/python

import socket
import sys

if len(sys.argv) != 2:
        print "Usage: vrfy.py <username file>"
        sys.exit(0)

#open user file
file=open(sys.argv[1], 'r')
users=[x.strip() for x in file.readlines()]
file.close

#Just for debugging
print users

# Create a Socket
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the Server
connect=s.connect(('192.168.13.222',25))

for x in users:
        # VRFY a user
        s.send('VRFY ' + x + '\r\n')
        result=s.recv(1024)
        print result

# Close the socket
s.close()

4 个回答

2

我在解决同样的问题时也遇到了这个情况。
我几乎可以肯定@samplebias说得对。我发现我可以通过更加“折磨”这个系统来绕过“拖延”的问题,也就是每次都拆掉再重建每个连接:

#[ ...Snip... ]
import smtplib
#[ ...Snip... ]
for USER in open(opts.USERS,'r'):
    smtpserver = smtplib.SMTP(HOST,PORT)
    smtpserver.ehlo()
    verifyuser = smtpserver.verify(USER)
    print("%s %s:  %s") % (HOST.rstrip(), USER.rstrip(), verifyuser)
    smtpserver.quit()

我很好奇这种特别的“猛攻”在实际环境中是否有效,但我也很确定这样做会让一些人非常不高兴。

顺便说一下,python:自带工具。

3

s.recv 这个方法会一直等待,如果你的网络连接上没有更多的数据,它就会一直卡在那里,不会继续往下执行。
所以,你需要注意自己接收了多少数据。你得提前知道这些信息,这样客户端和服务器才能达成一致,知道要接收多大的数据。

9

很可能是你的SMTP服务器在限制你的客户端连接。这是一种防止客户端失控的措施,或者是防止客户端发送大量“无用”命令的方式。从Postfix smtpd的手册中可以看到:

   smtpd_junk_command_limit (normal: 100, stress: 1)
          The number of junk commands (NOOP, VRFY, ETRN or  RSET)  that  a
          remote  SMTP  client  can  send  before  the Postfix SMTP server
          starts to increment the error counter with each junk command.

当检测到一定数量的无用命令后,smtpd守护进程会在回复之前插入1秒的延迟。如果你有权限访问这个SMTP服务器,可以尝试使用strace命令,看看服务器是否在执行nanosleep系统调用。

下面是我在本地服务器上运行你的脚本时的跟踪记录。在发送了100个VRFY命令后,它开始在命令之间休眠。你的服务器可能会在大约15个无用命令后就开始限制:

nanosleep({1, 0}, 0x7fffda9a67a0)       = 0
poll([{fd=9, events=POLLOUT}], 1, 300000) = 1 ([{fd=9, revents=POLLOUT}])
write(9, "252 2.0.0 pat\r\n", 15)       = 15
poll([{fd=9, events=POLLIN}], 1, 300000) = 1 ([{fd=9, revents=POLLIN}])
read(9, "VRFY pat\r\n", 4096)           = 10

撰写回答