2011-11-26 9 views
1

파이썬으로 간단한 portscanner를 구현하려고합니다. 대기열에서 제공되는 포트를 스캔하는 여러 작업자 스레드를 작성하여 작동합니다. 결과를 다른 큐에 저장합니다. 모든 포트를 검사하면 스레드와 응용 프로그램이 종료됩니다. 그리고 여기에 문제가 있습니다. 포트 수가 적 으면 모든 것이 잘 작동하지만 200 개 이상의 포트를 스캔하려고하면 응용 프로그램이 교착 상태에 빠지게됩니다. 왜 그런지 모르겠습니다.Python 스레드에서 교착 상태가 발생했습니다.

class ConnectScan(threading.Thread): 
    def __init__(self, to_scan, scanned): 
     threading.Thread.__init__(self) 
     self.to_scan = to_scan 
     self.scanned = scanned 

    def run(self): 
     while True: 
      try: 
       host, port = self.to_scan.get() 
      except Queue.Empty: 
       break 
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      try: 
       s.connect((host, port)) 
       s.close() 
       self.scanned.put((host, port, 'open')) 
      except socket.error: 
       self.scanned.put((host, port, 'closed')) 
      self.to_scan.task_done() 


class ConnectScanner(object): 
    def scan(self, host, port_from, port_to): 
     to_scan = Queue.Queue() 
     scanned = Queue.Queue() 
     for port in range(port_from, port_to + 1): 
      to_scan.put((host, port)) 
     for i in range(20): 
      ConnectScan(to_scan, scanned).start() 
     to_scan.join() 

아무도 틀렸을 수도 있습니다. 또한 파이썬에서 이러한 스레딩 문제를 디버깅하는 방법에 대해 알아 보겠습니다.

답변

1

to_scan 대기열의 모든 항목이 사용되지 않고 task_done 메서드를 ConnectScanner의 차단을 해제하는 데 충분하지 않은 것으로 생각할 수 있습니다.

ConnectScan.run의 런타임 중에 catch 중이 아니며 스레드가 중간에 종료되는 예외가 발생할 수 있습니까?

+0

맞습니다. tast_done이 자주 자주 불리지 않았습니다. 그 이유는 필터링 된 포트에 연결하려고 시도하면 (즉, 응답을받지 못하기 때문에) 소켓이 예외를 throw하지 않고 영원히 기다릴 수 있기 때문입니다. 그건 내 교착 상태 였어. – j0ker

2

분명히 코드에 문제가없는 것은 아니지만 휴식 시간에 결코 깨지지 않을 것입니다. self.to_scan.get()은 Queue.Empty가 아닌 영원히 기다립니다. 스레드를 시작하기 전에 검사 할 포트가있는 대기열을로드하는 경우 모든 포트가 요청되었을 때 작업자 스레드를 올바르게 종료하도록 self.to_scan.get(False)으로 변경할 수 있습니다.

데몬이 아닌 스레드 (주 스레드가 종료 된 후에 프로세스가 계속 유지되는 스레드)가 있다는 사실과 결합하면 중단의 원인 일 수 있습니다. to_scan.join() 뒤에 인쇄를 시도하여 인쇄물이 멈추었는지 아니면 프로세스가 끝났는지 확인하십시오.

Ray가 말하길, socket.error 이외의 예외가 self.to_scan.get()self.to_scan.task_done() 사이에서 발생하면 join 호출이 중단됩니다. try/finally를 사용하도록 코드를 변경하는 것이 도움이 될 수 있습니다.

def run(self): 
    while True: 
     try: 
      host, port = self.to_scan.get(False) 
     except Queue.Empty: 
      break 

     try: 
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      try: 
       s.connect((host, port)) 
       s.close() 
       self.scanned.put((host, port, 'open')) 
      except socket.error: 
       self.scanned.put((host, port, 'closed')) 
     finally: 
      self.to_scan.task_done() 

일반적으로 멀티 스레드 프로세스 디버깅은 까다 롭습니다. 무한정 차단되는 것을 피하려고합니다. 시간 초과가 너무 짧아 절대 표시되지 않는 항목을 영원히 기다리지 않게하기 때문에 시끄러운 소리가 나는 것이 좋습니다. 따라서 self.to_scan.get, socket.connectto_scan.join 호출에 대한 시간 제한을 지정합니다.

주문 이벤트가 발생하면 logging을 사용하십시오. 인쇄는 다른 스레드에서 인터리브 될 수 있지만 로거는 스레드로부터 안전합니다.

마찬가지로, this recipe과 같은 것은 각 스레드에 대한 현재 스택 추적을 덤프하는 데 유용 할 수 있습니다.

파이썬에서 여러 스레드 디버깅을 지원하는 디버거는 사용하지 않았지만 일부는 here으로 나열되어 있습니다.

+0

tipps에 감사드립니다. 그들은 던져진 예외가 아니라 오히려 던져지지 않은 예외 였지만 해결책을 찾는데 도움이되었습니다. 내가 제안하고있는 디버깅 기술을 살펴 보겠습니다. – j0ker

관련 문제