Использование именованного канала с перекрытием в Python 3.7 - PullRequest
2 голосов
/ 26 марта 2019

Я использую Windows с Python 3.7 и пытаюсь асинхронно обмениваться данными, только строками, между процессами Python. Один из них работает бесконечно (получатель), другой может начинаться в любой момент, отправляет некоторые данные, а затем завершается (отправитель). Я пытаюсь использовать именованный канал для этого.

Мне удалось получить это, когда они работают синхронно (приемник ждет в заблокированном канале, пока не получит данные), однако у приемника есть другие вещи, которые нужно делать в идеале, ему не следует ждать все время. Также в какой-то момент может быть второй отправитель, поэтому заблокированный канал не очень хорош.

Код для получателя:

import os
import time
import sys
import win32pipe, win32file, pywintypes

pipe_name = r'\\.\pipe\mypipe' 

pipe = win32pipe.CreateNamedPipe(
        pipe_name,
        win32pipe.PIPE_ACCESS_DUPLEX | win32file.FILE_FLAG_OVERLAPPED,  # open mode 
        win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT, # pipe mode
        1, 65536, 65536, # max instances, out buffer size,  in buffer size
        0, # timeout
    None)


while 1:
    print("doing my other stuff")
    try:
        win32pipe.ConnectNamedPipe(pipe, pywintypes.OVERLAPPED())
    except pywintypes.error as e:
        if e.winerror == 232:   #disconnected pipe
            win32pipe.DisconnectNamedPipe(pipe)
            print("Disconnecting pipe")
        else:
            print(e)
    try:
        retval, msg = win32file.ReadFile(pipe, 0, pywintypes.OVERLAPPED())
        print(msg)
    except pywintypes.error as e:
        if e.winerror == 536: #Wating for connection
            print("waiting")
        elif e.winerror == 233: #no process on other side
            continue
    time.sleep(1)

Код отправителя:

import os
import time
import sys
import win32pipe, win32file, pywintypes


pipe_name = r'\\.\pipe\mypipe' 


for x in range(5):

    handle = win32file.CreateFile(
            pipe_name,
            win32file.GENERIC_READ | win32file.GENERIC_WRITE,
            0,
            None,
            win32file.OPEN_EXISTING,
            win32file.FILE_FLAG_OVERLAPPED,
            None
            )
    res = win32pipe.SetNamedPipeHandleState(handle, win32pipe.PIPE_READMODE_MESSAGE, None, None)
    print(f"sending {x}")
    win32file.WriteFile(handle, str.encode(f"hello world {x}"))
    win32file.CloseHandle(handle)
    time.sleep(2)

Сейчас оба могут работать и иметь некоторое соединение, но я не могу получить данные. Приемник может выполнять другие операции, отключать и повторно открывать канал, если что-то отправлено, но msg оказывается пустым. Если я остановлю его в отладчике и отправлю что-нибудь, значение msg получит «memory at 0x0 .......», которое я бы интерпретировал как своего рода указатель, но, как вы, вероятно, уже заметили, мое понимание каналов ограничено.

Здесь Я нашел хороший пример работающего канала синхронизации. Я изменил создание трубы на приемник, но это было не сложно. Я нашел несколько примеров асинхронных (перекрывающихся) каналов здесь , которые также были великолепны, но оставили меня с проблемой, с которой я сейчас сталкиваюсь.

Чтение с перекрывающегося канала все еще является задачей для win32file.ReadFile или я что-то пропустил?

Большое спасибо!

1 Ответ

0 голосов
/ 01 апреля 2019

Я нашел решение и хочу поделиться им, на тот случай, если кто-то еще столкнется с этой проблемой.Как выясняется, msg получает "память в 0x0 ......." является объектом memoryview , и его данные могут быть доступны через bytes(msg).

.проблема с моей командой ReadFile, поскольку буфер должен иметь значение> 0, чтобы достичь чего-либо.Теперь он читает каждый байт индивидуально и добавляет их в строку.Это, вероятно, не очень хорошая производительность, но это работает для меня, и это решает проблему необходимости обрезать конец, если сообщение короче длины буфера.

msg = ''
rtnvalue, data = win32file.ReadFile(pipe, 1, pywintypes.OVERLAPPED())
while rtnvalue == 234:
    msg = msg + bytes(data).decode('ASCII') 
    rtnvalue, data = win32file.ReadFile(pipe, 1, pywintypes.OVERLAPPED())
if rtnvalue == 0: #end of stream is reached
    msg = msg + bytes(data).decode('ASCII')
return msg
...