Non-blocking pipe reads in Windows Python

linux下很容易实现的方法在windows下行不通....windows下select不能操作管道
百度找了半天蛋都碎了,最后只能祭出google

感谢github!!!!看到github上的内容的时候  真是太开心了

参考来源
https://gist.github.com/techtonik/48c2561f38f729a15b7b

windows对应pipe的函数
https://msdn.microsoft.com/en-us/library/aa365781%28v=vs.85%29.aspx

举一反三,弄了两种写法,
第一种和github的一样
第二种写法用了PeekNamedPipe
还有一种写法可以用TransactNamedPipe,但是TransactNamedPipe要用到的一个结构体ctype.wintypes里没有封装,所以就算了
顺便linux写法也丢上去了



点击(此处)折叠或打开

  1. # -*- coding: UTF-8 -*-
  2. __author__ = 'loliz_000'


  3. import msvcrt
  4. import platform
  5. import time
  6. from _exception import CmdException


  7. def read_line_thread_unix(fileobj, switch):
  8.     import select
  9.     while 1:
  10.         if switch['switch']:
  11.             break
  12.         try:
  13.             read_list, write_list, error_list = select.select([fileobj], [], [], 0.01)
  14.         except OSError:
  15.             break
  16.         except IOError:
  17.             break
  18.         except select.error:
  19.             break
  20.         if len(read_list) > 0:
  21.             output = read_list[0].readline()
  22.             if not output:
  23.                 break
  24.             print output
  25.             switch['out_line_list'].append(output)


  26. def read_line_thread_windows1(fileobj, switch):
  27.     import time
  28.     from ctypes import windll, byref, GetLastError, WinError
  29.     # 将指定类型转化为参数类型的函数
  30.     from ctypes.wintypes import POINTER
  31.     # 载入windows handle类型
  32.     from ctypes.wintypes import HANDLE as HANDLE_TYPE
  33.     # 载入windows dword类型
  34.     from ctypes.wintypes import DWORD as DWORD_TYPE
  35.     # 载入window是bool类型
  36.     from ctypes.wintypes import INT as INT_TYPE
  37.     # DWORD类型指正
  38.     LPDWORD_TYPE = POINTER(DWORD_TYPE)
  39.     # pipe nowait参数, dword 类
  40.     PIPE_NOWAIT = DWORD_TYPE(0x00000001)
  41.     # pipe 为空时的返回码
  42.     ERROR_NO_DATA = 232
  43.     # 定位SetNamedPipeHandleState函数
  44.     SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
  45.     # 确定SetNamedPipeHandleState的参数类型
  46.     SetNamedPipeHandleState.argtypes = [HANDLE_TYPE, LPDWORD_TYPE, LPDWORD_TYPE, LPDWORD_TYPE]
  47.     # 确定SetNamedPipeHandleState的返回值类型
  48.     SetNamedPipeHandleState.restype = INT_TYPE
  49.     # 管道的handle值
  50.     handle = msvcrt.get_osfhandle(fileobj.fileno())
  51.     # 设置管道非阻塞
  52.     res = SetNamedPipeHandleState(handle, byref(PIPE_NOWAIT), None, None)
  53.     # 设置结果
  54.     if res == 0:
  55.         raise CmdException('set no block pipe read catch error %s' % str(WinError()))
  56.     # 开始从管道读取数据
  57.     while 1:
  58.         if switch['switch']:
  59.             break
  60.         try:
  61.             string_buff = fileobj.readline()
  62.         except OSError:
  63.             if GetLastError() != ERROR_NO_DATA:
  64.                 break
  65.             else:
  66.                 raise CmdException('read from pipe catch error %s' % str(WinError()))
  67.         if len(string_buff) == 0:
  68.             time.sleep(0.001)
  69.             continue
  70.         else:
  71.             print string_buff


  72. def read_line_thread_windows2(fileobj, switch):
  73.     from ctypes import windll, byref, GetLastError, WinError
  74.     # 将指定类型转化为参数类型的函数
  75.     from ctypes.wintypes import POINTER
  76.     # 载入windows handle类型
  77.     from ctypes.wintypes import HANDLE as HANDLE_TYPE
  78.     # 载入windows dword类型
  79.     from ctypes.wintypes import DWORD as DWORD_TYPE
  80.     # 载入window是bool类型
  81.     from ctypes.wintypes import INT as INT_TYPE
  82.     # LPVOID_TYPE指针
  83.     from ctypes.wintypes import LPVOID as LPVOID_TYPE
  84.     # DWORD类型指正
  85.     LPDWORD_TYPE = POINTER(DWORD_TYPE)
  86.     # 期望读取长度
  87.     BUFFER_SHOULD_BE_RES = DWORD_TYPE(4096)
  88.     # 实际读取长度
  89.     BUFFER_SIZE_RES = DWORD_TYPE(0)
  90.     # 实际发送长度
  91.     BUFFER_SIZE_SEND = DWORD_TYPE(0)
  92.     # pipe 为空时的返回码
  93.     ERROR_NO_DATA = 232
  94.     # 定位PeekNamedPipe函数
  95.     PeekNamedPipe = windll.kernel32.PeekNamedPipe
  96.     # 确定PeekNamedPipe的参数类型
  97.     PeekNamedPipe.argtypes = [HANDLE_TYPE, LPVOID_TYPE, DWORD_TYPE, LPDWORD_TYPE, LPDWORD_TYPE, LPDWORD_TYPE]
  98.     # 确定PeekNamedPipe的返回值类型
  99.     PeekNamedPipe.restype = INT_TYPE
  100.     # 管道的handle值
  101.     handle = msvcrt.get_osfhandle(fileobj.fileno())
  102.     # 开始从管道读取数据
  103.     while 1:
  104.         if switch['switch']:
  105.             break
  106.         # 获取管道信息
  107.         res = PeekNamedPipe(handle, None, BUFFER_SHOULD_BE_RES,
  108.                             byref(BUFFER_SIZE_RES), byref(BUFFER_SIZE_SEND), None)
  109.         # 设置结果
  110.         if res == 0:
  111.             print 'get end!!'
  112.             break
  113.             #raise CmdException('set no block pipe read catch error %s' % str(WinError()))
  114.         if BUFFER_SIZE_RES.value <= 0:
  115.             time.sleep(0.001)
  116.             continue
  117.         else:
  118.             try:
  119.                 gg = fileobj.read(BUFFER_SIZE_RES.value)
  120.                 print gg
  121.             except OSError:
  122.                 if GetLastError() != ERROR_NO_DATA:
  123.                     break
  124.                 else:
  125.                     raise CmdException('read from pipe catch error %s' % str(WinError()))
  126.         #print gg.decode('gbk')
  127.         #print 'finsh'


  128. if platform.system() == 'windows':
  129.     read_line_thread = read_line_thread_unix
  130. else:
  131.     read_line_thread = read_line_thread_windows1



10-04 06:39