Pyro4 介绍,利用其实现进程间类方法的互相调用

笔者需要实现一个进程调用另外一个进程中类的方法,通过python库Pyro4解决此问题。

实际需求是这样的,有一个测试中心控制类,负责处理其他进程对其类方法的调用。其他进程通过Pyro4库调用测试中心类的方法。

Pyro4:以socket通信为基础,利用类序列化和反序列化方法,实现本机进程间通信,亦可实现局域网内不同机器进程间的通信。

http://pythonhosted.org/Pyro4/ 这是官网地址,想要深入学习的可以瞅瞅。

简单的说,Pyro4分为server和client两端,server一般是提供方法调用的一方,pyro4 server启动后,会使用局域网广播将本机注册到pyro4 server上的类方法广播

给其他pc或本机其他进程。client 根据特定的uri连接到特定的pyro4 server,client调用pyro4 server上注册的方法,就跟调用本地代码一样,如果调用方法阻塞,便会等pyro4 server上

的方法执行完后,client取到结果后,才会继续往下执行。

利用uri实现server和client间通信

client code

#!/usr/bin/python
# -*- coding: utf-8 -*-

import Pyro4
uri=raw_input(" Pyro uri : ").strip() //输入server端uri
name=raw_input("Your name: ").strip()
greeting_maker=Pyro4.Proxy(uri)
print greeting_maker.get_fortune(name)

server code

#!/usr/bin/python
# -*- coding: utf-8 -*-

import Pyro4
class GreetingMaker(object):
    def get_fortune(self, name):
        return "Hello, {0}. \n" .format(name)
greeting_maker=GreetingMaker()
daemon=Pyro4.Daemon()
uri=daemon.register(greeting_maker)
print "Ready. Object uri =", uri      //此处的uri需要告知client
daemon.requestLoop()

以上的代码便是一个说明pyro4的简单demo,但在实际项目中,server端每次生成的uri都是变化的,client不能够通过uri调用server端的代码。

其实,pyro4 提供了一个nameserver的方法,其类似于ip地址的域名解析,client 只需要将uri替换成一个pyro4 server声明的字符串即可,client回到nameserver中找寻此字符串对应

的类方法。server 将需要被调用的类方法暴露出去,并注册到nameserver中即可。

以下是通过nameserver中介的程序

server端

#!/usr/bin/python
# coding:utf-8
import Pyro4

@Pyro4.expose #将此类暴露给client
class GreetingMaker(object):
    def __init__(self,name):
        print ‘this is %s‘ % name
    def get_fortune(self, name):
        return "Hello, {0}. Here is your fortune message:\n"                "Tomorrow‘s lucky number is 12345678.".format(name)

daemon = Pyro4.Daemon()                # make a Pyro daemon
ns = Pyro4.locateNS()                  # find the name server
uri = daemon.register(GreetingMaker(‘lyh‘))   # register the greeting maker as a Pyro object
ns.register("example.greeting", uri)   # register the object with a name in the name server

print("Ready.")
daemon.requestLoop()                   # start the event loop of the server to wait for calls

client 端

#!/usr/bin/python
# coding:utf-8
import Pyro4

name = input("What is your name? ").strip()

greeting_maker = Pyro4.Proxy("PYRONAME:example.greeting")    # use name server object lookup uri shortcut
print(greeting_maker.get_fortune(name))

命令行启动nameserver:python -m Pyro4.naming

以下是笔者项目中实际的rmi_server

#!/usr/bin/python
# -*- coding: utf-8 -*-

import Pyro4
import psutil
import subprocess
import traceback
import time
import threading
import multiprocessing
import os
import common_func

from awlib import atc_net_serial_com
from slave_logger import Logger

logger = Logger("RmiServer")

MAINCOM = [‘COM11‘, ‘COM21‘]
UARTCOM = [‘COM29‘, ‘COM28‘, ‘COM27‘, ‘COM26‘, ‘COM25‘, ‘COM24‘, ‘COM23‘, ‘COM22‘,
           ‘COM19‘, ‘COM18‘, ‘COM17‘, ‘COM16‘, ‘COM15‘, ‘COM14‘, ‘COM13‘, ‘COM12‘]

class RmiServer(multiprocessing.Process):
    """Remote classmethod call server
    @register net uart COM11 COM21
    @brocast port 9091, listen port 9090

    """

    def start(self):
        # start rmi nameserver
        net_ip = common_func.get_netcard()[0][1]
        exists_python_pids_before = common_func.get_pids_by_name(‘python‘)
        # broadcast method, all local area network pc can connect to it
        # pyro4_cmd = ‘python -m Pyro4.naming -n %s‘ % net_ip
        # start pyro4 server on localhost
        pyro4_cmd = ‘python -m Pyro4.naming‘
        # set Pyro4 server threadpool size unlimit
        Pyro4.config.SERVERTYPE="multiplex"
        p_pyro4 = subprocess.Popen(pyro4_cmd, shell=True)
        time.sleep(1)
        exists_python_pids_after = common_func.get_pids_by_name(‘python‘)
        self.kill_pids = []
        for pid_after in exists_python_pids_after:
            if pid_after not in exists_python_pids_before:
                self.kill_pids.append(pid_after)

        # self.pyro4_daemon = Pyro4.Daemon(host=net_ip)   # make a Pyro daemon
        self.pyro4_daemon = Pyro4.Daemon()
        try:
            # find the broadcast name server use specify ip
            # self.ns = Pyro4.locateNS(host=net_ip)
            # find the name server
            self.ns = Pyro4.locateNS()
        except:
            traceback.print_exc()
        else:
            logger.info(‘connect to RmiNameServer successfully‘)
        # register classmethod
        self._register_net_uart()
        # run rmiserver thread
        t_run = threading.Thread(target=self._run)
        t_run.setDaemon(True)
        t_run.start()

    def stop(self):
        try:
            self.pyro4_daemon.shutdown()
            self.pyro4_daemon.close()
            for kill_pid in self.kill_pids:
                os.kill(kill_pid, 9)
        except:
            pass

        logger.info(‘stop RmiServer successfully‘)

    def _run(self):
        self.pyro4_daemon.requestLoop()  # start the event loop of the server to wait for calls

    def _register(self, cls_md, cls_md_str):
        uri = self.pyro4_daemon.register(cls_md)
        self.ns.register(cls_md_str, uri)

    def _register_net_uart(self, wait_connect_time=6):
        logger.warn(‘********************Init MainCOM and DUT uart will take more time, please wait***********************‘)
        for maincom in MAINCOM:
            self._register(atc_net_serial_com.MainComCaller(maincom), maincom)
        time.sleep(wait_connect_time)
        logger.info(‘****************************************Init MainCOM and DUT uart OK!!!******************************‘)
if __name__ == ‘__main__‘:
    rmi_server = RmiServer()
    rmi_server.start()

上面是一个本地进程间通信的例子,其中注释掉的

# broadcast method, all local area network pc can connect to it
# pyro4_cmd = ‘python -m Pyro4.naming -n %s‘ % net_ip
# self.pyro4_daemon = Pyro4.Daemon(host=net_ip)   # make a Pyro daemon
# find the broadcast name server use specify ip
# self.ns = Pyro4.locateNS(host=net_ip)

实现局域网内不同PC进程间通信的例子

一个利用pyro4 client 例子

class NetSerialUSBAllInOneSwitch():
    """support operate atc_g1 without virtual serial
    """

    def __init__(self, maincom=None):
        self.main_com = Pyro4.Proxy("PYRONAME:" + maincom)

    def switch2power(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_usb_power‘, lines=[line])
        return cmd_result

    def switch2usb(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_usb_power_signal‘, lines=[line])
        return cmd_result

    def switch2off(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘close_usb‘, lines=[line])
        return cmd_result

    def switch2dcoff(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_off_ext_power‘, lines=[line])
        return cmd_result

    def switch2dc5v(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_ext_power‘, lines=[line], dict_arg={‘voltage‘: 5})
        return cmd_result

    def switch2dc12v(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_ext_power‘, lines=[line], dict_arg={‘voltage‘: 12})
        return cmd_result

    def switch2otg(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_otg_signal‘, lines=[line])
        return cmd_result

    def switch2otg5v(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_otg_5v‘, lines=[line])
        return cmd_result

    def keypress(self, line, number, value):
        cmd_result = None
        line = int(line)
        number = int(number)
        value = int(value)
        cmd_result = self.main_com.run_cmd(maincom_method=‘key_control‘, lines=[
                                           line], dict_arg={‘num‘: number, ‘status‘: value})
        return cmd_result

    def switch2ext12v(self, line):
        cmd_result = None
        line = int(line)
        cmd_result = self.main_com.run_cmd(maincom_method=‘turn_on_ext_12vdc‘, lines=[line])
        return cmd_result

    def get_pyro4_maincom(self):
        return self.main_com

    def close(self):
        self.main_com._pyroRelease() # 调用pyro4内置方法,关闭pyro4 client 连接

  

时间: 2024-10-07 04:06:57

Pyro4 介绍,利用其实现进程间类方法的互相调用的相关文章

.Net 利用消息在进程间通讯实现进程互操作

有时候我们会遇到需要在两个进程间通过某种方式实现互操作,方法有很多,例如你可以尝试让两个进程持续监视一个外部文件,由此文件记录各自进程的数据:还有可以使用网络端口实现进程间通讯.共享一片内存区域记录及传递各自进程的数据等:此处讲述在.net 下如何利用消息的传递及处理实现两个进程的通讯. 是的,这里所说的消息指的就是Windows的消息机制,对于 I T 菜鸟,可以这样简单理解Windows 消息机制:Windows系统可以同时运行很多很多应用程序,Windows系统要让某一个程序做一件事情,就

Android Studio创建AIDL文件并实现进程间通讯

在Android系统中,跨进程通信是非常普遍的事情,它用到了Binder机制处理进程之间的交互.Binder机制会开放一些接口给java层,供android开发工程师调用进程之间通信.这些接口android封装到了AIDL文件里,当我们项目用到跨进程通信时可以创建.aidl文件,.aidl文件可以协助我们达到跨进程的通信.下面简单介绍用AndroidStudio创建AIDL文件的过程. a.新建AIDL文件 1.项目文件夹右键---> new --->选择AIDL 2.自定义一个接口名称 3.

利用内存映射文件在两个进程间共享数据 转

private hMapFile: THandle; MapFilePointer: Pointer; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin hMapFile := CreateFileMapping ( $FFFFFFFF, // 特殊内存映射句柄 nil, page_

【转】VC 利用DLL共享区间在进程间共享数据及进程间广播消息

1.http://blog.csdn.net/morewindows/article/details/6702342 在进程间共享数据有很多种方法,剪贴板,映射文件等都可以实现,这里介绍用DLL的共享区间在进程间共享数据,及共享数据有变化时及时的反馈给各相关进程. 一.在DLL中设置共享区间 在DLL中是用数据段来实现共享区间的,有了这个共享区间,各进程可以方便的共享数据. 1.先用#pragma data_seg(Name)设置名为Name的数据段. 2.再用#pragma comment(l

利用QSystemSemaphore和QSharedMemory实现进程间通讯

https://blog.csdn.net/liji_digital/article/details/70547082 线程间的通讯可以由QSemaphore调控,以保证各个线程对同一资源的访问不冲突. 但是进程间的协调就不能利用QSemaphore,而要利用QSystemSemaphore. 此外,在同一进程内的各个线程之间可以用信号-槽机制通信,但是进程之间就不可以了.取而代之的是QSharedMemory. 下面的两个程序test_process和ProcessClient运行在不同的进程

C#进程间通讯技术-整理。

原文:C#进程间通讯技术-整理. 扩展阅读:http://www.cnblogs.com/joye-shen/archive/2012/06/16/2551864.html 一.进程间通讯的方式 1)共享内存 包括:内存映射文件,共享内存DLL,剪切板. 2)命名管道及匿名管道 3)消息通讯 4)利用代理方法.例如SOCKET,配置文件,注册表方式. 等方式. 方法一:通讯. 进程间通讯的方式有很多,常用的有共享内存(内存映射文件.共享内存DLL.剪切板等).命名管道和匿名管道.发送消息等几种方

Android使用Messenger实现进程间双向通信

在了解本文即将学到的技能外,有些知识还是有必要提前知道的,这样才会更容易理解本文即将讲到的知识点.需要提前预热的知识点: 1.Android四大组件之一Service,要知道怎样去写一个Service,Service有哪两种启动方式: 2.Android Service启动方式之Bound Service: 3.Android基础知识之Messenger: 掌握了这三个知识点,就可以快速入手使用Messenger进行进程间通信了. 一.知识点回顾之Service 我们来看看官方文档关于对Serv

windows核心编程之进程间共享数据

有时候我们会遇到window进程间共享数据的需求,例如说我想知道系统当前有多少某个进程的实例. 我们能够在程序中定义一个全局变量.初始化为0.每当程序启动后就加1.当然我们我们能够借助第三方介质来储存这个变量,然后解析. 这样做必须做到先写入后解析.不能实时更新数据.假设不考虑其它储存介质.仅仅是进程中的通信,应该怎么做呢?windows提供了一些可行的方法,以下介绍经常使用的两种. 一.共享数据段 #include "stdafx.h" #include <Windows.h&

Nginx学习——Nginx进程间的通信

nginx进程间的通信 进程间消息传递 共享内存 共享内存还是Linux下提供的最主要的进程间通信方式,它通过mmap和shmget系统调用在内存中创建了一块连续的线性地址空间,而通过munmap或者shmdt系统调用可以释放这块内存.使用共享内存的优点是当多个进程使用同一块共享内存时,在不论什么一个进程改动了共享内存中的内容后,其它进程通过訪问这段共享内存都可以得到改动后的内容. Nginx定义了ngx_shm_t结构体.用于描写叙述一块共享内存, typedef struct{ //指向共享