用Python操作Named pipe命

发布时间:2019-09-10 08:47:24编辑:auto阅读(1989)

            在我以前做过的用于手游服务器的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。这样网络就联系起来了。和匿名管道的架构是一致的。

关键字