示例:一个简单的程序,每10秒打印一次列表的值
import argparse
import time
import sys
myList = []
def parseArguments():
parser = argparse.ArgumentParser(description="example")
parser.add_argument('-a', '--addElement', help='adds an element to the list')
args = parser.parse_args()
if args.addElement:
myList.append(args.addElement)
def main():
parseArguments()
while(True):
print(myList)
time.sleep(10)
问题是程序只读取在启动时传递的参数,我希望它在运行时随时读取传递的参数。
我想像服务一样在后台运行程序,并每隔一段时间向程序传递参数。
我知道您所要求的看起来像是一个能够接受异步命令的服务(或守护进程(。
外部接口:
prog foo
=>ok重复打印['foo']
稍后:
程序条
=>第二个实例退出,第一个实例重复打印['foo', 'bar']
内部设计
这绝非易事!您需要设置一个IPC机制,以允许第二个实例和第一个实例通信,在第一个实例中使用非阻塞IO(或多线程(。在Unix下,您可以使用os.mkfifo
,但如果您想要一个可移植的解决方案,则必须使用localhost 上的IP套接字
高级伪码的结构
get argument via argparse
bind to a fix port on localhost, in UDP protocol
if success:
# ok it is the first prog
initialize list from argument
loop:
get command from UDP socket, with timeout = 10s
if cmd is add param:
add parameter to list
elif cmd is exit: # not asked in question but should exist
exit
print list
else:
# another prog has taken the socket, pass it the arg
send the arg to the UDP port with proper protocol
关于这个简单设计的注意事项:存在竞争条件,即在第一次尝试绑定和发送之间,套接字上已经有一个程序在等待。要处理这个问题,您应该使用TCP协议,在侦听套接字上使用带有超时的select
,并优雅地关闭以确保在另一端接收到消息。在出现错误的情况下,您需要迭代(最大次数(,因为第一台服务器可能会在一段时间内退出。
下面是一个实现示例:
import socket
import select
import argparse
import time
import sys
TIMEOUT=10
IFACE='127.0.0.1'
PORT=4000
DEBUG=False
myList = []
old = ""
def parseArguments():
parser = argparse.ArgumentParser(description="example")
parser.add_argument('-a', '--addElement',
help='adds an element to the list')
parser.add_argument('-q', '--quit', action='store_true',
help='closes main service')
parser.add_argument('-d', '--debug', action='store_true',
help='display debug information')
args = parser.parse_args()
if args.quit:
senddata("QUITn")
sys.exit(0)
if args.debug:
DEBUG=True
if args.addElement:
myList.append(args.addElement)
def read(s):
global old
data = old
while True:
block = s.recv(1024)
if len(block) == 0: return data
if b'n' in block:
block,o = block.split(b'n', 1)
old = o.decode()
data += block.decode()
return data
data += block.decode()
def gracefulclose(s, msg):
s.send(msg.encode())
s.shutdown(socket.SHUT_WR)
try:
read(s)
finally:
s.close()
def server(s):
if DEBUG:
print("SERVER")
s.listen(5)
while True:
sl = select.select([s], [], [], TIMEOUT)
if len(sl[0]) > 0:
s2, peer = s.accept()
try:
data = read(s2)
print(data)
gracefulclose(s2, "OK")
finally:
s2.close()
if data.startswith("QUIT"):
return
elif data.startswith("DATA:"):
myList.append(data[5:])
print(myList)
def senddata(data):
s = socket.socket(socket.AF_INET)
try:
s.connect((IFACE, PORT))
s.send(data.encode())
data = read(s)
if (data.startswith("OK")):
return True
except:
pass
finally:
s.close()
return False
def client():
return senddata("DATA:" + myList[0] + "n")
def main():
end = False
MAX = 5
while not end and MAX > 0:
s = socket.socket(socket.AF_INET)
try:
s.bind((IFACE, PORT))
except Exception:
s.close()
s = None
if s:
try:
server(s)
finally:
s.close()
return
else:
if DEBUG:
print("CLIENT", " ", 6 - MAX)
end = client()
MAX -= 1
time.sleep(1)
if __name__ == "__main__":
parseArguments()
main()
import argparse
import time
import sys
myList = []
def parseArguments():
parser = argparse.ArgumentParser(description="example")
parser.add_argument('-a', '--addElement', help='adds an element to the list')
args = parser.parse_args()
if args.addElement:
myList.append(args.addElement)
def main():
parseArguments()
import select
while(True):
while select.select([sys.stdin], [], [], 0)[0]:
myList.append(sys.stdin.readline().strip())
print(myList)
time.sleep(10)
如果在执行过程中传递了更多的参数,则必须从stdin中读取它们。使用select模块,您可以检查stdin中是否有新行,然后将它们添加到myList中。
基本上,您要问的是如何进行进程间通信(IPC(。
我为什么这么说?好吧,你自己回答:你想如何将这些论点传递给你的后台服务?手工我不这么认为(因为这样你就有了一个简单的交互式程序,只需要等待用户输入(。您可能需要其他一些脚本/程序,通过某种命令按需发送这些参数。
通常有几种方法可以通信两个或多个程序,最流行的是:
共享文件-您只需检查磁盘上文件的内容即可。此解决方案的优点是,您可以使用自己喜欢的文本编辑器编辑此文件,而无需编写客户端应用程序。
管道-一个程序读取其输入,这是另一个程序的输出。您应该简单地阅读sys.stdin.
# receiver
def read_input():
for l in sys.stdin:
yield l
套接字-通过网络接口发送的数据流(但可以在同一台机器上本地发送(。Python文档对套接字编程有很好的介绍。
共享内存-您的程序读取/写入相同的内存块。在Python中,您可以使用mmap模块来实现这一点。
无论您选择哪种方式来沟通流程,都应该在它们之间建立某种接口。它可以是一个非常简单的基于文本的界面,比如这个:
# command syntax
<command> SPACE <parameter> NEWLINE
SPACE := 0x20 # space character
NEWLINE := 0x0A # 'n' character
# a command adding element to receiver's list
ADD SPACE <element> NEWLINE
# a command removing element from receiver's list:
REMOVE SPACE <element> NEWLINE
# examples:
ADD first elementn
REMOVE first elementn
因此,例如,如果你通过套接字发送消息(我建议这样做(,你的接收者(服务器(应该读取缓冲区,直到出现换行符,然后检查第一个单词是否为"ADD",然后将剩余字符(减去换行符(添加到你的列表中。当然,你应该为某种"攻击"做好准备——比如你应该指定你的消息不能超过4096字节。通过这种方式,您可以在当前缓冲区达到限制后丢弃它,这意味着在等待换行符时不会无限期地分配内存。这是一条非常重要的规则:不要相信用户的输入。
祝你好运!:(