2009-03-03 11 views
5

Ich habe eine Frage. Ich würde gerne eine kontinuierliche Byteströme an einen Host für eine bestimmte Zeit senden (sagen wir 1 Minute) mit Python.Python: wie Pakete in Multi-Thread zu senden und dann der Thread sich selbst töten

Hier ist mein Code so weit:

#! /usr/bin/env python               

import socket 
import thread 
import time 

IP = "192.168.0.2" 
PADDING = "a" * 1000 #assume the MTU is slighly above 1000 
DATA = PADDING + "this is sentence number = " 
PORT = 14444 
killed = False 
test_time = 60 #60 seconds of testing 

def send_data(): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect((IP, PORT)) 
    count = 1 
    starttime = time.clock() 
    while elapsed < test_time: 
    sent = s.send(DATA + str(count) + "\n") 
    if sent == 0: break # assume that if nothing is sent -> connection died 
    count = count+1 
    elapsed = time.clock() - starttime 
    if killed: 
     break 
    s.close() 
    print str(count) + " has been sent" 

print "to quit type quit" 
thread.start_new_thread(send_data,()) 

while True: 
    var = raw_input("Enter something: ") 
    if var == "quit": 
    killed = True 

Wenige Frage, gibt es einen besseren Weg, um einen Faden stirbt nach 60 Sekunden außer Abfrage des time.clock jedes Mal zu lassen? Wenn ich dieses Programm ausführen, sendet es die Bytes korrekt, aber wenn ich getippt habe, wird der andere Thread nicht sterben, obwohl ich die var killed = True gesetzt habe. Ich frage mich, warum ist das so? der Umfang von var Killed sollte den anderen Thread richtig erreichen? Stellen Sie sicher,

Dank

+0

Existiert tatsächlich ein Host unter dieser Adresse? Verwenden Sie Netcat, um die Ausgabe oder ein anderes Programm zu erfassen? – johnny

+0

Ich denke, dass der Umfang von "getötet" in Ordnung ist. – Jiri

Antwort

0

, dass die „quit“ ordnungsgemäß funktioniert und fügen Sie einen kleinen Druck zu testen, ob die Eingabe funktioniert.

if var == "quit": 
print "Hey we got quit" 
0

Die Variable verstrichene nicht initialisiert wird. Setze es über der While-Schleife auf Null.

2

Ich weiß nicht, wie dies zu tun mit dem „Faden“ Modul, aber ich kann es mit dem „Einfädeln“ Modul tun. Ich denke, dieser Code erfüllt, was Sie wollen.

Für die Dokumentation auf dem Threading-Modul: http://docs.python.org/library/threading.html

#!/usr/bin/python 

import time 
from threading import Thread 
import threading 
import sys 

test_time = 10 
killed = False 

class SillyThread(threading.Thread): 
    def run(self): 
     global killed 
     starttime = time.time() 
     counter = 0 
     while (time.time() - starttime) < test_time: 
      if killed: 
       break 
      counter = counter + 1 
      time.sleep(0.1) 
     print "I did %d loops" % counter 

class ManageThread(threading.Thread): 
    def run(self): 
     global killed 
     while True: 
      var = raw_input("Enter something: ") 
      if var == "quit": 
       killed = True 
       break 
     print "Got var [%s]" % var 

silly = SillyThread() 
silly.start() 
ManageThread().start() 
Thread.join(silly) 
print "bye bye" 
sys.exit(0) 

Bitte beachte, dass ich time.time() verwenden, statt time.clock(). time.clock() gibt die verstrichene Prozessorzeit unter Unix an (siehe http://docs.python.org/library/time.html). Ich denke time.clock() sollte überall funktionieren. Ich setze meine test_time auf 10 Sekunden, weil ich für eine Minute keine Geduld habe.

Hier ist, was passiert, wenn ich es die vollen 10 Sekunden laufen lassen:

[email protected]:~/tmp$ ./test.py 
Enter something: I did 100 loops 
bye bye 

Hier ist, was passiert, wenn ich tippe ‚beenden‘:

[email protected]:~/tmp$ ./test.py 
Enter something: quit 
Got var [quit] 
I did 10 loops 
bye bye 

Hoffnung, das hilft.

1

Wie oben erwähnt, verwenden Sie das threading Modul, es viel einfacher zu bedienen ist und bietet mehrere Synchronisations Primitiven. Es bietet auch eine Timer Klasse, die nach einer bestimmten Zeit ausgeführt wird.

Wenn Sie nur möchten, dass das Programm beendet wird, können Sie den sendenden Thread einfach zum Daemon machen. Dazu rufen Sie setDaemon (True) auf, bevor Sie start() aufrufen (2.6 könnte stattdessen ein Daemon-Attribut verwenden). Python wird nicht beendet, solange ein Nicht-Daemon-Thread ausgeführt wird.

5

Ich empfehle die Verwendung von Threading-Modul. Ein weiterer Vorteil ist die Verwendung von InterruptableThread zum Beenden des Threads. Sie müssen flag nicht zum Beenden Ihres Threads verwenden, aber es wird eine Ausnahme auftreten, wenn Sie terminate() in diesem Thread von parent aufrufen. Sie können mit Ausnahme umgehen oder nicht.

import threading, ctypes 

class InterruptableThread(threading.Thread): 
@classmethod 
def _async_raise(cls, tid, excobj): 
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj)) 
    if res == 0: 
     raise ValueError("nonexistent thread id") 
    elif res > 1: 
     ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0) 
     raise SystemError("PyThreadState_SetAsyncExc failed") 

def raise_exc(self, excobj): 
    assert self.isAlive(), "thread must be started" 
    for tid, tobj in threading._active.items(): 
     if tobj is self: 
      self._async_raise(tid, excobj) 
      return 

def terminate(self): 
    self.raise_exc(SystemExit) 

EDIT: Sie Ihren Code wie folgt unter Verwendung eines anderen Thread neu schreiben kann, die mit 1 Minute warten und dann anderen Thread zu töten

def send_data: 
    IP = ... 
    # other vars 

    ... 
    s = socket.socket(.....) 

    # no killed checking 
    # no time checking 
    # just do your work here 
    ... 
    s.close() 


my_thread = InterruptableThread(target=send_data) 
my_thread.start() 

def one_minute_kill(who): 
    time.sleep(60) 
    who.terminate() 

killer_thread = InterruptableThread(target=one_minute_kill, args=[my_thread]) 
killer.start() 

print "to quit type quit" 
while my_thread.isAlive(): 
    if raw_input("Enter something: ") == "quit": 
    my_thread.terminate() 
+1

Beachten Sie, dass Sie den ersten Parameter von "PyThreadState_SetAsyncExc" in einem Aufruf von "ctypes.c_long" umbrechen müssen, damit dieser Code unter 64-Bit-Systemen (64-Bit-Linux) funktioniert. Andernfalls wird es als 32-Bit-Ganzzahl übergeben, die überläuft, und Sie erhalten eine "nicht vorhandene Thread-ID" ValueError Ausnahme. – intuited

0

Es ist einfach, den Umfang der killed zu testen:

>>> import thread 
>>> killed = False 
>>> import time 
>>> def test(): 
... while True: 
... time.sleep(1) 
... if killed: 
...  print 'Dead.' 
...  break 
... 
>>> thread.start_new_thread(test,()) 
25479680 
>>> time.sleep(3) 
>>> killed = True 
>>> Dead. 
1

Sie können dies ziemlich einfach ohne Threads tun. Zum Beispiel mit Verdreht, setzen Sie nur einen zeitlich abgestimmten Anruf und einen Produzenten:

from twisted.internet.protocol import ClientFactory, Protocol 
from twisted.internet import reactor 

class Noisy(Protocol): 
    def __init__(self, delay, data): 
     self.delay = delay 
     self.data = data 

    def stop(self): 
     self.transport.unregisterProducer() 
     self.transport.loseConnection() 
     reactor.stop() 

    def resumeProducing(self): 
     self.transport.write(self.data) 

    def connectionMade(self): 
     self.transport.registerProducer(self, False) 
     reactor.callLater(self.delay, self.stop) 

factory = ClientFactory() 
factory.protocol = lambda: Noisy(60, "hello server") 
reactor.connectTCP(host, port, factory) 
reactor.run() 

Diese verschiedene Vorteile gegenüber dem Gewindeansatz hat. Es ist nicht auf Daemon-Threads angewiesen, so dass Sie die Netzwerkverbindung tatsächlich bereinigen können (um z. B. eine Close-Nachricht zu senden), anstatt sich auf die Plattform zu verlassen, um sie zu zerstören. Es handhabt den ganzen Netzwerkcode der niedrigen Stufe für Sie (Ihr ursprüngliches Beispiel tut die falsche Sache im Fall von socket.send, das 0 zurückgibt; dieser Code behandelt diesen Fall richtig). Sie müssen sich auch nicht auf ctypes oder die obskure CPython-API verlassen, um eine Ausnahme in einem anderen Thread auszulösen (daher ist sie zu mehr Versionen von Python portierbar und kann einen blockierten Sendevorgang im Gegensatz zu einigen der anderen vorgeschlagenen Ansätze sofort unterbrechen).