用Python操作Named pipe命
在我以前做过的用于手游服务器的python服务器框架里,我用了Python的multiprocessing库,多进程通信用了multiprocessing提供的最方便的queue,实际上就是一种匿名管道。要求管道两端的进程必须是父子进程或者兄弟进程。
匿名管道给后续扩展带来影响,无法动态的增加或者减少服务进程。如果可以动态增加减少进程,至少在非严重故障时重启服务器会方便很多。
之前研究了一阵命名管道,遇到很多问题。这两天有空再次试验,想明白了很多。直接看例子。
客户端 Client.py:
# named pipe Client
#encoding: utf-8
import os
import time
write_path = "/tmp/server_in.pipe"
read_path = "/tmp/server_out.pipe"
counter = 1
f = os.open( write_path, os.O_SYNC | os.O_CREAT | os.O_RDWR )
print "Client open f", f
rf = None
while True:
# Client发送请求
req = "%s "%counter
len_send = os.write( f, req )
print "request", req, len_send
counter += 1
if rf == None:
# *要点1:在这里第一次打开read_path,实际这里的open是一个阻塞操作
# 打开的时机很重要。如果在程序刚开始,没发送请求就打开read_path,肯定会阻塞住
rf = os.open( read_path, os.O_RDONLY )
print "client opened rf", rf
# 接收Server回应
s = os.read( rf, 1024 )
if len(s) == 0:
# 一般来说,是管道被意外关闭了,比如Server退出了
break
print "received", s
# 这个例子里没有sleep,客户端以最高速度发送数据,可以观察执行效果
os.close( f )
os.close( rf )
服务器 Server.py:
#named pipe Server
#encoding: utf-8
import os, time
read_path = "/tmp/server_in.pipe"
write_path = "/tmp/server_out.pipe"
try:
# 创建命名管道
os.mkfifo( write_path )
os.mkfifo( read_path )
except OSError, e:
# 如果命名管道已经创建过了,那么无所谓
print "mkfifo error:", e
# 写入和读取的文件,正好和Client相反
rf = os.open( read_path, os.O_RDONLY )
f = os.open( write_path, os.O_SYNC | os.O_CREAT | os.O_RDWR )
while True:
# 接收请求
s = os.read( rf, 2 )
if len(s) == 0:
# 没有收到字符,一般是唯一的发送方被关闭了。
# 这里可以休息一下继续,对后续消息没有任何影响,也不会丢包。
time.sleep( 1 )
continue
# 如果收到的字符串带一个s,打印出来
# 用于调试和测试
if "z" in s:
print "received", s
# 在请求前面加一个s字母,返回
os.write( f, "s%s"%s )
os.close( f )
os.close( rf )
这个例子具有一定实用性:
1、无论先执行Server.py还是Client.py都可以正常工作。
2、Server.py与Client.py执行时,可以在另一个控制台里输入 echo zzzzz > /tmp/server_in.pipe,可以观察到,server可以同时处理多个来源的请求
3、实际上在进程交互时,每个进程既是一个Client又是一个Server,每个进程只有一个用于接收别人请求的pipe,然后接收请求后把处理结果返回给发送方的pipe。这样网络就联系起来了。和匿名管道的架构是一致的。
相关文章