Python для цикла замедляется и даже зависает - PullRequest
5 голосов
/ 21 апреля 2011

Я совершенно новичок в Python (по состоянию на полчаса назад) и пытаюсь написать простой скрипт для перечисления пользователей на SMTP-сервере.

Файл пользователей представляет собой простой список (по одному на строку)) имен пользователей.

Сценарий работает нормально, но с каждой итерацией цикла он замедляется до тех пор, пока, вокруг цикла 14, кажется, что он не зависает полностью.Нет ошибок - я должен ^ c.

Кто-нибудь может пролить свет на проблему, пожалуйста?

TIA, Том

#!/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 ]

8 голосов
/ 21 апреля 2011

Скорее всего, ваш SMTP-сервер нарушает ваше клиентское соединение.Это защита от сбежавших клиентов или клиентов, которые отправляют большие объемы «мусорных» команд.С man-страницы для 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-секундную задержку перед ответом после того, как будет замечено определенное количество мусора.Если у вас есть root-доступ к рассматриваемому серверу 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
3 голосов
/ 21 апреля 2011

s.recv блокируется, поэтому, если у вас больше нет данных в сокете, он будет блокироваться навсегда.
Вы должны отслеживать, сколько данных вы получаете.Вы должны знать это заранее, чтобы клиент и сервер могли согласовать размер.

2 голосов
/ 30 мая 2012

Решая точно такую ​​же проблему, я тоже столкнулся с этой проблемой.Я почти уверен, что @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()

Мне интересно, будет ли этот конкретный тип удара работать в реальной среде, но слишком уверен, что это сделает некоторых людей очень несчастными.

PS, python: батареи включены.

1 голос
/ 21 апреля 2011

На первый взгляд в вашем коде нет ошибок. Однако вы должны заметить, что TCP не является протоколом, ориентированным на сообщения. Таким образом, вы не можете использовать socket.send в цикле, предполагая, что одно сообщение будет фактически отправляться через среду при каждом вызове. Таким образом, если некоторые вызовы начинают буферизироваться в выходном буфере, а вы просто вызываете socket.recv после него, ваша программа застревает в тупике.

Что вам нужно сделать, это многопоточный или асинхронный код. Возможно, Twisted Framework может вам помочь.

...