Python 运行 MessageQueue.Peek via win32com,如何让超时正确?

Python running MessageQueue.Peek via win32com, how to get timeout right?

对于初学者,我想说如果有人能在这里提供帮助,你真是太棒了。

一般问题

我的 Python 程序需要与 MSMQ 交互。基本上,我想查看队列,如果队列中没有任何内容,则指定超时。

然而,尽管我尽了最大努力,但当队列中先前没有值时,我无法让 Peek() 等待超时间隔。 能否请您指出此代码中缺少的内容?


我的当前代码

这是我现在的代码:

from socket import gethostname

import win32com.client
import pythoncom

import clr
clr.AddReference("System")
clr.AddReference("System.Messaging")
from System import TimeSpan
from System.Messaging import MessageQueue


# Source: [1]
# [1] https://docs.microsoft.com/en-us/previous-versions/windows/desktop/msmq/ms707027%28v%3dvs.85%29
MQ_DENY_NONE = 0x0
MQ_PEEK_ACCESS = 0x1
MQ_SEND_ACCESS = 0x2


# Set up queue
pythoncom.CoInitialize()
qinfo = win32com.client.Dispatch("MSMQ.MSMQQueueInfo")
qinfo.FormatName = f"direct=os:{gethostname()}\PRIVATE$\MyQueue"
queue = qinfo.Open(MQ_PEEK_ACCESS, MQ_DENY_NONE)

# Receive a value
timeout_sec = 1.0
timespan = TimeSpan.FromSeconds(timeout_sec)
label, body = "", ""
# TODO: timeout value does not appear working. It never waits when
#  there's no message
if queue.Peek(pythoncom.Empty, pythoncom.Empty, timespan):
    msg = queue.Receive() . # Blocking receive --> remove msg from the queue
    if msg is not None:
        label = msg.Label
        body = msg.Body

我运行:inspect.getfullargspec(queue.Peek)并得到:

FullArgSpec(args=['self', 'WantDestinationQueue', 'WantBody', 'ReceiveTimeout', 'WantConnectorType'], varargs=None, varkw=None, defaults=(<PyOleMissing object at 0x00000147F5D43BD0>, <PyOleMissing object at 0x00000147F5D43BD0>, <PyOleMissing object at 0x00000147F5D43BD0>, <PyOleMissing object at 0x00000147F5D43BD0>), kwonlyargs=[], kwonlydefaults=None, annotations={})

我尝试过的事情

This question: 说 ReceiveTimeout=timespan 似乎没有解决我的问题。

pythoncom.Missing 替换 pythoncom.Empty 似乎不起作用

This unanswered question 和我的很像

我找到了这篇文章 sending-msmq-messages-python

本文向您展示了如何使用 msmq 发送和接收消息。我不明白为什么你不能只使用标准套接字连接语法来说明如果我没有收到 packet/connection 然后关闭连接

import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
    data = mysocket.recv(4096)

所以类似的事情应该不会太难。最坏的情况是创建一个线程,检查每个 timeout_time 变量是否为零。如果它是零关闭队列,如果它 >0 设置为零并等待更多消息,则不会收到任何消息。 我还找到了一个关于 python 日志记录的异步 msmq 的 GitHub。 asynchronous msmq 这个刚刚说接收 while True dlopes7 msmq

import time
t_end = time.time() + 60 * 15
messages=0
while time.time() < t_end or messages>0:
    msg = queue.Receive()
    messages+=1
    if(time.time() > t_end and messages>0):
        messages=0
        t_end = time.time() + 60 * 15
    print(f'Got Message from {queue_name}: {msg.Label} - {msg.Body}')

不是您想要的答案,而是一个可行的答案。

在原始问题的评论中,@PeterBrittain 建议尝试使用:

an integer (in milliseconds) for their timeout

我抽空尝试了一下,实际上,它奏效了!我发现 float 值也适用。这是一些示例 Python 代码:

timeout_sec = 1.0
queue.Peek(pythoncom.Empty, pythoncom.Empty, timeout_sec * 1000):

谢谢@PeterBrittain!