Python线程不想关闭

时间:2013-01-28 23:13:10

标签: python multithreading

我的程序有问题。

我设法找到了问题的根源。问题在于方法“checkPort”。没有它,关闭/终止线程的标准教科书方法非常有效。

我错过了什么吗?在checkPort方法中是什么阻止成功加入线程?它始终停留在thread.join()

主程序的一部分

try:
    queue = Queue.Queue()

    for i in range(MAX_THREAD_COUNT):
        t = checkPort_IPv6_thread(queue)
        t.daemon = True
        threads.append(t)
        t.start()

    cur.execute("SELECT * FROM ipv6")
    results = cur.fetchall()
    for row in results:
        queue.put((row[0], row[2]))

    queue.join()

    for thread in threads:
        thread.stop()
        thread.join()

except Exception as e:
    sys.stderr.write("Error: " + str(e))
    print

print "\nChecking ports for IPv6 - DONE"

这是线程类,我调用checkPort方法:

class checkPort_IPv6_thread(threading.Thread):
    def __init__(self,queue):
        threading.Thread.__init__(self)
        self.queue = queue
        self.keepRunning = True

    def run(self):
        while self.keepRunning:
            args = self.queue.get()
            id = args[0]
            address = args[1]
            port443 = 0
            port21 = 0 
            port80 = 0 

            #---------------- Check ports for IPv6 ----------------
            if str(address) != "N/A":
                port443 = checkPort("TCP",str(address), 443)
                port21 = checkPort("TCP",str(address), 21)
                port80 = checkPort("TCP",str(address), 80)

            lock.acquire()
            try:
                cur.execute("UPDATE ipv6 SET port_443=" + str(port443) + " WHERE id_ipv6 =" + str(id))
                cur.execute("UPDATE ipv6 SET port_21=" + str(port21) + " WHERE id_ipv6 =" + str(id))
                cur.execute("UPDATE ipv6 SET port_80=" + str(port80) + " WHERE id_ipv6 =" + str(id))
                db.commit()

            except Exception as e:
                sys.stderr.write("Error: " + str(e))
            except:
                db.rollback()
            lock.release()

            self.queue.task_done()


    def stop(self):
        self.keepRunning = False

checkPort方法

def checkPort(typ, address, port):
    if typ == "TCP":
        s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    else:
        s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    pom = 0 # 0/1 = True/False
    try:
        s.settimeout(2) # timeout 1.5 sekundy
        s.connect((str(address), port))
        s.settimeout(None)
        #time.sleep(0.5)
        pom = 1
        print str(address) + " >> on port: " + str(port) + " >> Connection was successfull"

    except socket.timeout:
        print str(address) + " >> on port: " + str(port) + " >> * Error: Timed out *"
    except socket.error as e:
        if e.errno == 10061:
            print str(address) + " >> on port: " + str(port) + " >> * No connection could be made - target machine refused it *"
    except Exception as ex:
        sys.stderr.write("Error: " + str(ex))

    return pom

2 个答案:

答案 0 :(得分:1)

以下内容可以帮助您完成您的计划。它是为Python 3.x编写的。我认为主要问题在于您的计划的args = self.queue.get()行。它应该固定在下面。

import multiprocessing
import queue
import threading
import sys
import socket

MAX_THREAD_COUNT = multiprocessing.cpu_count()

def main(cur):
    cur.execute("""UPDATE ipv6
                      SET port_21 = 0,
                          port_80 = 0,
                          port_443 = 0
                    WHERE address = 'N/A'""")
    q = queue.Queue()
    for _ in range(MAX_THREAD_COUNT):
        CheckPort(q).start()
    cur.execute("""SELECT id_ipv6,
                          address
                     FROM ipv6
                    WHERE address != 'N/A'""")
    for row in cur.fetchall():
        q.put(row)
    q.join()
    for thread in threading.enumerate():
        if isinstance(thread, CheckPort):
            thread.stop()
            thread.join()

class CheckPort(threading.Thread):

    def __init__(self, q):
        super().__init__()
        self.__q = q
        self.__run = True

    def stop(self):
        self.__run = False

    def run(self):
        while self.__run:
            try:
                id, address = self.__q.get(True, 1)
            except queue.Empty:
                continue
            with lock:
                try:
                    cur.execute('''UPDATE ipv6
                                      SET port_21 = ?,
                                          port_80 = ?,
                                          port_443 = ?
                                    WHERE id_ipv6 = ?''',
                                self.check_port(address, 21),
                                self.check_port(address, 80),
                                self.check_port(address, 443),
                                id)
                    db.commit()
                except Exception as error:
                    print('Error:', error, file=sys.stdout)
                self.__q.task_done()

    @staticmethod
    def check_port(address, port):
        sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        sock.settimeout(2)
        try:
            sock.connect((address, port))
        except socket.timeout:
            return 0
        else:
            sock.shutdown(socket.SHUT_RDWR)
            sock.close()
            return 1

if __name__ == '__main__':
    try:
        main(cur)
    except Exception as error:
        print('Error:', error, file=sys.stdout)

答案 1 :(得分:0)

从OP的编辑到他的问题:


<强>解决方案:

感谢Noctis Skytower解决方案是catch queue.empty exception

try:
    id, address = self.queue.get(True, 1)
except Queue.Empty:
    continue