如何通过在后台运行的程序读取参数



示例:一个简单的程序,每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字节。通过这种方式,您可以在当前缓冲区达到限制后丢弃它,这意味着在等待换行符时不会无限期地分配内存。这是一条非常重要的规则:不要相信用户的输入。

祝你好运!:(

相关内容

  • 没有找到相关文章

最新更新