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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 连接

  

 

以上是关于Pyro4 介绍,利用其实现进程间类方法的互相调用的主要内容,如果未能解决你的问题,请参考以下文章

应用进程实现对其他应用程序的调用

Nodejs中调用系统命令Shell脚本的方法和实例

java中时间类的详细总结

golang 调用windows API 中文的处理

如何检查 Pyro4 客户端是不是还活着

通过系统调用,内核断点方法定位用户进程被内核踩内存的问题