使用PHP来简单的创建一个RPC服务

RPC全称为Remote Procedure Call,翻译过来为"远程过程调用"。主要应用于不同的系统之间的远程通信和相互调用。

比如有两个系统,一个是PHP写的,一个是JAVA写的,而PHP想要调用JAVA中的某个类的某个方法,这时候就需要用到RPC了。

怎么调?直接调是不可能,只能是PHP通过某种自定义协议请求JAVA的服务,JAVA解析该协议,在本地实例化类并调用方法,然后把结果返回给PHP。

这里我们用PHP的socket扩展来创建一个服务端和客户端,演示调用过程。

RpcServer.php代码如下:

<?php
class RpcServer {
    protected $serv = null;

    public function __construct($host, $port, $path) {
        //创建一个tcp socket服务
        $this->serv = stream_socket_server("tcp://{$host}:{$port}", $errno, $errstr);
        if (!$this->serv) {
            exit("{$errno} : {$errstr} \n");
        }
        //判断我们的RPC服务目录是否存在
        $realPath = realpath(__DIR__ . $path);
        if ($realPath === false || !file_exists($realPath)) {
            exit("{$path} error \n");
        }

        while (true) {
            $client = stream_socket_accept($this->serv);

            if ($client) {
                //这里为了简单,我们一次性读取
                $buf = fread($client, 2048);
                //解析客户端发送过来的协议
                $classRet = preg_match(‘/Rpc-Class:\s(.*);\r\n/i‘, $buf, $class);
                $methodRet = preg_match(‘/Rpc-Method:\s(.*);\r\n/i‘, $buf, $method);
                $paramsRet = preg_match(‘/Rpc-Params:\s(.*);\r\n/i‘, $buf, $params);

                if($classRet && $methodRet) {
                    $class = ucfirst($class[1]);
                    $file = $realPath . ‘/‘ . $class . ‘.php‘;
                    //判断文件是否存在,如果有,则引入文件
                    if(file_exists($file)) {
                        require_once $file;
                        //实例化类,并调用客户端指定的方法
                        $obj = new $class();
                        //如果有参数,则传入指定参数
                        if(!$paramsRet) {
                            $data = $obj->$method[1]();
                        } else {
                            $data = $obj->$method[1](json_decode($params[1], true));
                        }
                        //把运行后的结果返回给客户端
                        fwrite($client, $data);
                    }
                } else {
                    fwrite($client, ‘class or method error‘);
                }
                //关闭客户端
                fclose($client);
            }
        }
    }

    public function __destruct() {
        fclose($this->serv);
    }
}

new RpcServer(‘127.0.0.1‘, 8888, ‘./service‘);

RpcClient.php代码如下:

<?php

class RpcClient {
    protected $urlInfo = array();

    public function __construct($url) {
        //解析URL
        $this->urlInfo = parse_url($url);
        if(!$this->urlInfo) {
            exit("{$url} error \n");
        }
    }

    public function __call($method, $params) {
        //创建一个客户端
        $client = stream_socket_client("tcp://{$this->urlInfo[‘host‘]}:{$this->urlInfo[‘port‘]}", $errno, $errstr);
        if (!$client) {
            exit("{$errno} : {$errstr} \n");
        }
        //传递调用的类名
        $class = basename($this->urlInfo[‘path‘]);
        $proto = "Rpc-Class: {$class};" . PHP_EOL;
        //传递调用的方法名
        $proto .= "Rpc-Method: {$method};" . PHP_EOL;
        //传递方法的参数
        $params = json_encode($params);
        $proto .= "Rpc-Params: {$params};" . PHP_EOL;
        //向服务端发送我们自定义的协议数据
        fwrite($client, $proto);
        //读取服务端传来的数据
        $data = fread($client, 2048);
        //关闭客户端
        fclose($client);
        return $data;
    }
}

$cli = new RpcClient(‘http://127.0.0.1:8888/test‘);
echo $cli->hehe();
echo $cli->hehe2(array(‘name‘ => ‘test‘, ‘age‘ => 27));

然后分别运行上面两个脚本(注意,php要添加环境变量)

> php RpcServer.php
> php RpcClient.php

结果如下:

Test.php代码如下:

<?php
class Test {
    public function hehe() {
        return ‘hehe‘;
    }
    public function hehe2($params) {
        return json_encode($params);
    }
}

目录结构如下:

上面我们自定义的协议,可以随意修改,只要是客户端和服务端两边能够统一并能解析。

客户端通过请求服务端,把要调用的类,方法和参数传递给服务端,服务端去通过实例化调用方法返回结果。

时间: 2024-10-10 17:44:15

使用PHP来简单的创建一个RPC服务的相关文章

C# 创建一个WCF服务

做代码统计,方便以后使用: app.config配置文件设置: <configuration> <system.serviceModel> <bindings> <webHttpBinding> <binding name="webBinding" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMess

为MongoDB创建一个Windows服务

一:选型,根据机器的操作系统类型来选择合适的版本,使用下面的命令行查询机器的操作系统版本 wmic os get osarchitecture 二:下载并安装 附上下载链接 点击安装包,我这里是把文件安装到了(E:\MongoDB) 安装好之后该文件夹下就出现下面的文件, 这个时候新建一个Data文件夹用来存放MongoDB的所有数据,新建一个Log文件夹用来存放日志文件 三:启动MongoDB数据库,在命令行窗口执行下面的命令,执行完成之后会看到下面的提示信息 e:\mongodb\bin\m

docker 简单创建一个tomcat服务

上一篇已经介绍了docker相关的基本命令,这篇我们来详细介绍下通过docker如何创建一个toncat应用容器.方法一:如果不想自己搭建tomcat应用容器的话,可以直接在Docker Hub上直接search tomcat ,如下图:docker search tomcat可以看到有好多的内容,如果搜索结果显示有相关镜像,则可以直接通过 docker pull tomcat 来下载 tomcat镜像.docker pull tomcat 当提示下载完毕时,我们可以通过docker image

在windows下创建一个Mongo服务

首先需要下载mongo的安装包 cmd.exe 这个需要用管理员权限打开 进入到mongo的安装目录 首先到C盘根据下面的命令手动创建一个 Data 文件夹 在Data 里面创建一个db文件夹一个log文件夹 mongod   表示执行mongo的命令 -dbpath   表示创建数据库文件 -logpath  表示创建日志文件 -install  -serviceName    表示创建的这个服务的名字 “” 中的是数据库的文件和日志的文件 创建数据库文件和创建日志文件的时候如果指定的路径中的

[翻译] 使用 .NET Core 3.0 创建一个 Windows 服务

原文: .NET Core Workers as Windows Services 在 .NET Core 3.0 中,我们引入了一种名为 Worker Service 的新型应用程序模板.此模板旨在为您在 .NET Core 中编写长时间运行的服务的提供一个起点.在本演练中,我们将创建一个 worker 并将其作为 Windows 服务运行. 创建一个 Worker 注意:在我们的预览版中,worker 模板与 Web 模板位于同一级菜单中.这将在未来的版本中发生变化.我们打算将 Worker

【SpringBoot】使用IDEA创建一个SpringBoot服务,并创建三个restful风格的接口

项目创建: 选择创建一个springboot项目: 输入一下项目信息,一般就是maven的信息填一下: 选择spring web starter: 然后finish就OK了. 编码: 演示的功能就是提供一个计数器功能,可以初始化计数器,修改计数器,查询计数器当前值.没有使用数据库,直接用一个单例类来模拟了,项目结构如下: Count: 1 package com.me.redis.resouce.bean; 2 3 public class Count { 4 private int count

简单的创建一个性能计数器

一.性能监控的作用 性能监控可以用于获取关于应用程序的正常行为的一般消息,性能监控是一个强大的工具,有助于理解系统的工作负载,观察变化和趋势,尤其是运行在服务器上的应用程序 二.性能监控类(System.Diagnostics):PerformanceCounter类:监控计数与写入计数.还可以使用这个类创建新的性能类别PerformanceCounterCategory类:可以查看所有的已有的类别,以及创建类别.可以以编程的方式获得一个类别中的所有计数器performanceCounterIn

python (知识点:类)简单的创建一个类

#!/usr/bin/env python # -*- coding: utf-8 -*- """ Created on Mon Nov 14 01:01:29 2016 @author: toby """ #知识点:类和对象 #名词:1.实例化一个类,生成一个对象,通过类进行实例化来生成一个对象 class Animal:     body = 'Four legs' class Human: #类的名称     body = 'Hands, 

用Express简单创建一个Mock服务

安装express: 1 npm install --save express 安装Mockjs: 1 npm install mockjs 建立MockServer.js文件: 1 let express = require('express'); //引入express 2 let Mock = require('mockjs'); //引入mock 3 4 let app = express(); //实例化express 5 6 app.use(function(req, res, ne