不断运行的Python脚本,通过终端调用函数

0 投票
5 回答
910 浏览
提问于 2025-04-16 21:14

我有个小问题,其实我都不太确定这是否可能 :3

我有一个Python脚本,这是一个网络脚本,它会连接到一个服务器,并保持连接,直到我手动断开或者服务器把我踢掉(通常不应该发生这种情况)。这个脚本会不断接收数据,还会执行其他任务。

我想知道在脚本运行的时候,是否可以从脚本内部触发某些功能?比如说,当脚本在运行时,如果我突然想要发送一些数据到服务器,我能不能直接输入这些数据,然后把它发送给处理这部分的函数?

我不太确定这是否可行,因为我从来没有尝试过,也没见过有人这样做。如果有帮助的话,我是在Ubuntu Linux上通过终端运行这个脚本的。

5 个回答

1

看看这个 gevent

gevent 是一个基于协程的 Python 网络库,它使用 greenlet 来提供一个高级的同步接口,这个接口是在 libevent 事件循环之上的。

还有 gevent.socket

1

通常解决这类问题的“UNIX方式”是使用 pollselect,这两个方法可以同时监控网络连接和标准输入。这样的话,当网络有数据进来时,你就能在套接字的“输入”事件上处理这些数据,而当终端有输入时,你则在 stdin 文件描述符的“输入”事件上处理。

不过,这种方法在Windows上不太适用(这真让人失望),但在类UNIX系统上,这是最自然的做法。而且,这样做可以避免使用线程时常见的一些问题(在Python中,线程如果不进行轮询的话,可能会变得“无法终止”)。

1

Jacek Konieczny的解决方案很好也很简单。如果你想要更灵活的消息传递方式,可以考虑一下ZeroMQ。这个工具能让你轻松创建各种消息传递的解决方案,围绕你的主程序进行开发。使用一个线程,你的主程序大概会是这样的:

#!/usr/bin/env python

import zmq
from time import sleep

CTX = zmq.Context()

incoming = CTX.socket(zmq.PULL)
incoming.bind("tcp://127.0.0.1:3000")

outgoing = CTX.socket(zmq.PUB)
outgoing.bind("tcp://127.0.0.1:3001")

# Poller for the incoming messages
poller = zmq.Poller()
poller.register(incoming, zmq.POLLIN)

def main():
    while True:
        # Do things on the network
        print("[Did things on the network]")
        # Send messages if you want
        outgoing.send("Important message")
        # Poll for incoming messages
        socks = dict(poller.poll(zmq.NOBLOCK))
        if incoming in socks and socks[incoming] == zmq.POLLIN:
            message = incoming.recv()
            # Handle message
            print("[Handled message '%s']" % message)

        sleep(1) # Only for this dummy program

if __name__ == "__main__":
    main()

接下来,你需要写一个客户端(可以用任何支持ZeroMQ的编程语言),这个客户端会从主程序中推送和订阅消息。下面是一个推送者的例子:

#!/usr/bin/env python

import zmq

CTX = zmq.Context()

pusher = CTX.socket(zmq.PUSH)
pusher.connect("tcp://127.0.0.1:3000")

def main():
    pusher.send("Message to main program")

if __name__ == "__main__":
    main()

还有一个订阅者的例子:

#!/usr/bin/env python

import zmq

CTX = zmq.Context()

subscriber = CTX.socket(zmq.SUB)
subscriber.connect("tcp://127.0.0.1:3001")
subscriber.setsockopt(zmq.SUBSCRIBE, "")

def main():
    while True:
        msg = subscriber.recv()
        print("[Received message] %s" % msg)

if __name__ == "__main__":
    main()

听起来你可能想把推送者和订阅者的程序合并成一个。如果你决定使用ZeroMQ,可以看看这个很棒的用户指南

当然,你也可以在多个线程或进程中使用ZeroMQ(只要注意不要在不同线程之间共享单独的ZeroMQ套接字)。

撰写回答