我有一个问题。我想使用python向一些主机发送连续的字节流一段时间(假设1分钟)。
到目前为止,这是我的代码:
#! /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
很少有问题,除了每次轮询time.clock之外,有没有更好的方法让线程在60秒后死亡? 当我运行这个程序时,它正确地发送字节,但是当我键入退出时,另一个线程不会死,即使我设置了var killed = True。我想知道为什么会这样? var Killed的范围应该到达另一个线程吗?
由于
答案 0 :(得分:5)
我推荐使用线程模块。更有利的是使用InterruptableThread来终止线程。您不必使用标志来终止您的线程,但如果您从父线程调用此线程上的terminate(),则会发生异常。你可以处理异常。
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)
修改强> 您可以使用另一个等待1分钟然后杀死其他线程的线程重写您的代码
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 :(得分:2)
我不知道如何使用“thread”模块执行此操作,但我可以使用“threading”模块执行此操作。我认为这段代码可以实现你想要的。
有关线程模块的文档: 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)
请注意,我使用time.time()而不是time.clock()。 time.clock()给出了Unix上经过的处理器时间(参见http://docs.python.org/library/time.html)。我认为time.clock()应该无处不在。我将test_time设置为10秒,因为我没有耐心一分钟。
如果我让它运行整整10秒,会发生什么:
leif@peacock:~/tmp$ ./test.py
Enter something: I did 100 loops
bye bye
如果我输入'quit',会发生什么:
leif@peacock:~/tmp$ ./test.py
Enter something: quit
Got var [quit]
I did 10 loops
bye bye
希望这有帮助。
答案 2 :(得分:1)
如上所述,使用threading模块,它更容易使用,并提供了几个同步原语。它还提供了一个Timer类,它在指定的时间后运行。
如果您只想让程序退出,您可以简单地将发送线程作为守护程序。您可以在调用start()之前调用setDaemon(True)来执行此操作(2.6可能会使用守护程序属性)。只要非守护程序线程正在运行,Python就不会退出。
答案 3 :(得分:1)
没有线程,你可以很容易地做到这一点。例如,使用Twisted,您只需设置定时调用和生产者:
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()
与线程方法相比,这有许多优点。它不依赖于守护程序线程,因此您实际上可以清理网络连接(例如,在必要时发送关闭消息),而不是依靠平台来销毁它。它为您处理所有实际的低级网络代码(在socket.send返回0的情况下,您的原始示例正在做错事;此代码将正确处理该情况)。您也不必依赖ctypes或模糊的CPython API来在另一个线程中引发异常(因此它可以移植到更多版本的Python并且实际上可以立即中断阻塞的发送,这与其他一些建议的方法不同)。 / p>
答案 4 :(得分:0)
确保“退出”正常工作并添加一个小字体以测试输入是否正常。
if var == "quit":
print "Hey we got quit"
答案 5 :(得分:0)
未初始化已过去的变量。在while循环上方将其设置为零。
答案 6 :(得分:0)
测试killed
:
>>> 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.