windows select pipe

转载自:http://blog.youkuaiyun.com/chief1985/article/details/5064998

在进行socket编程时,经常会采用select或epoll来接受并发请求。在有些系统里面(例如嵌入式设备),是不支持epoll的,这时只能用select。

Select定义如下:
int select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct timeval *timeout);

在进行select的时候,如果等待的句柄没有发生变化和没有超时,select是会一直等待在那里的。但在某些情况下,你需要唤醒select,你会怎么办呢?在linux上,你可以将管道的句柄传给select,然后在要唤醒select的时候向管道里面写东西就可以了(palm pre手机里面就用了这种技巧,我是通过反汇编知道的)。但在windows平台下,你就不能将管道传给select了,这时你就需要用socket来模拟管道了。在windows pipe的模拟(http://blog.chinaunix.net/u2/69656/showart_705924.html里面,作者提供了一种在windows上模拟管道的方法,代码如下:

 

  1. int pipe(int fildes[2])  
  2. {  
  3.     int tcp1, tcp2;  
  4.     sockaddr_in name;  
  5.     memset(&name, 0, sizeof(name));  
  6.     name.sin_family = AF_INET;  
  7.     name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);  
  8.     int namelen = sizeof(name);  
  9.     tcp1 = tcp2 = -1;  
  10.     int tcp = socket(AF_INET, SOCK_STREAM, 0);  
  11.     if (tcp == -1){  
  12.         goto clean;  
  13.     }  
  14.     if (bind(tcp, (sockaddr*)&name, namelen) == -1){  
  15.         goto clean;  
  16.     }  
  17.     if (listen(tcp, 5) == -1){  
  18.         goto clean;  
  19.     }  
  20.     if (getsockname(tcp, (sockaddr*)&name, &namelen) == -1){  
  21.         goto clean;  
  22.     }  
  23.     tcp1 = socket(AF_INET, SOCK_STREAM, 0);  
  24.     if (tcp1 == -1){  
  25.         goto clean;  
  26.     }  
  27.     if (-1 == connect(tcp1, (sockaddr*)&name, namelen)){  
  28.         goto clean;  
  29.     }  
  30.     tcp2 = accept(tcp, (sockaddr*)&name, &namelen);  
  31.     if (tcp2 == -1){  
  32.         goto clean;  
  33.     }  
  34.     if (closesocket(tcp) == -1){  
  35.         goto clean;  
  36.     }  
  37.     fildes[0] = tcp1;  
  38.     fildes[1] = tcp2;  
  39.     return 0;  
  40. clean:  
  41.     if (tcp != -1){  
  42.         closesocket(tcp);  
  43.     }  
  44.     if (tcp2 != -1){  
  45.         closesocket(tcp2);  
  46.     }  
  47.     if (tcp1 != -1){  
  48.         closesocket(tcp1);  
  49.     }  
  50.     return -1;  
  51. }  
 

在这段代码里面,有一个技巧是:将port设为0,然后进行bind,再接着通过getsockname来获取port。这可以满足获取随机端口的情况。

### Python `multiprocessing.Pipe` 的常见问题及解决方案 在使用 Python 中的 `multiprocessing.Pipe` 时,可能会遇到一些常见的阻塞或通信失败的问题。以下是针对这些问题的原因分析以及可能的解决方案。 #### 原因分析 1. **双向通讯中的阻塞问题** 当使用默认的双向管道 (`duplex=True`) 时,如果两端都在等待对方发送数据而未及时读取,则可能导致死锁现象[^3]。 2. **单向通讯中的阻塞问题** 如果仅需单向通讯却未关闭另一端的连接,发射端会一直尝试写入直到缓冲区满为止,从而造成阻塞行为。 3. **跨平台差异** Windows 和 Unix/Linux 平台对于文件描述符处理方式不同,在某些情况下需要特别注意如何设置非阻塞模式[^1]。 --- #### 解决方案 ##### 方法一:通过关闭不需要的一端来避免阻塞 当只需要单向传输时,应该显式地关闭不使用的那一侧管道连接对象以防止潜在的阻塞风险。 ```python from multiprocessing import Process, Pipe def sender(conn): conn.send("Hello from Sender!") conn.close() # 关闭当前端口以释放资源并通知接收方结束消息流 if __name__ == "__main__": parent_conn, child_conn = Pipe(duplex=False) # 设置为单工模式 p = Process(target=sender, args=(child_conn,)) p.start() print(parent_conn.recv()) # 接收来自子进程的消息 p.join() ``` ##### 方法二:利用异步机制实现非阻塞操作 可以借助于标准库模块如 `select`, 或者更现代的方式采用协程框架 `asyncio` 来管理 I/O 多路复用事件循环,以此达到真正的无阻效果。 ```python import os import time from select import select from multiprocessing import Process, Pipe def async_sender(pipe_out): while True: ready_to_read, _, _ = select([pipe_out], [], [], 0) if not ready_to_read: break try: msg = input("Enter message:") pipe_out.send(msg) except EOFError as e: pass if __name__ == '__main__': recv_end, send_end = Pipe(False) proc = Process(target=async_sender, args=(send_end,)) proc.daemon = True proc.start() start_time = time.time() timeout_duration = 5 # seconds while (time.time()-start_time)<timeout_duration: readable,_,_ = select([recv_end],[],[],0) if readable: data = recv_end.recv() print(f'Received {data}') proc.terminate() ``` 上述例子展示了基于 `select()` 函数监听多个输入源状态变化的能力,并结合超时参数控制整个交互过程不会陷入无限期停滞状况之中. ##### 方法三:继承自定义类扩展功能 另一种思路是从基类派生新的子类重载其内部方法逻辑以便更好地满足特定需求场景下的灵活定制化要求[^2]. ```python class CustomProcess(Process): def run(self): super().run() self.pipe_connection.close() # 自动清理不再需要的部分 # Example usage omitted here... ``` --- ### 总结 以上介绍了几种有效应对多进程中管道通信可能出现的各种异常情形的办法。实际开发过程中应根据具体业务特点选择最合适的策略组合运用起来才能最大程度提升程序健壮性和用户体验满意度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值