Gitlib Gitlib
首页
  • 分类
  • 标签
  • 归档
  • Golang开发实践万字总结
  • MySQL核心知识汇总
  • Redis实践总结
  • MQ实践万字总结
  • Docker数据持久化总结
  • Docker网络模式深度解读
  • 常用游戏反外挂技术总结
  • 读书笔记
  • 心情杂货
  • 行业杂谈
  • 友情链接
关于我
GitHub (opens new window)

Ravior

以梦为马,莫负韶华
首页
  • 分类
  • 标签
  • 归档
  • Golang开发实践万字总结
  • MySQL核心知识汇总
  • Redis实践总结
  • MQ实践万字总结
  • Docker数据持久化总结
  • Docker网络模式深度解读
  • 常用游戏反外挂技术总结
  • 读书笔记
  • 心情杂货
  • 行业杂谈
  • 友情链接
关于我
GitHub (opens new window)
  • PHP

    • PHP-FPM使用指南
    • PHP7新特性总结
    • PHP安全编程
    • PHP安全配置总结
    • PHP变量的值类型和引用类型
    • PHP标准规范PSR
    • PHP操作Zookeeper实践
    • PHP错误和异常处理机制详解
    • PHP的Session运行机制
    • PHP底层运行机制和原理
    • PHP反射模拟实现注解路由
    • PHP高级用法总结
    • PHP开发常用文档总结
    • PHP开发入门:Memcached扩展安装
    • PHP开发入门:PHP7安装部署
    • PHP开发入门:Redis扩展安装
    • PHP开发SPL总结
    • PHP框架常见URL模式
    • PHP扩展开发入门
    • PHP垃圾回收机制
    • PHP类的自动加载
    • PHP输入输出流
    • PHP微服务开发指南
    • PHP协程
    • PHP写时拷贝技术
    • PHP性能优化之Opcache
    • PHP依赖注入和控制反转
    • PHP运行模式(SAPI)
    • PHP中file_get_contents与curl区别
    • RPC的简单实现
      • 什么是RPC
      • Socket服务端
      • Socket客户端
    • Protobuf:高效数据结构化工具
    • P3P协议详解
    • Laravel之集合(Collection)总结
    • Laravel实践总结
    • Laravel之ORM总结
    • 中高级PHP实践总结
    • PHP Socket编程实战
  • Golang

  • Python

  • Javascript

  • 其他语言

  • 编程语言
  • PHP
Ravior
2015-02-27
目录

RPC的简单实现

# 什么是RPC

RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

通俗点讲,RPC一般采用TCP/IP通信,按照约定的数据格式(协议),对远端服务器上的服务进行(例如:xx函数)调用, 使得程序能够像访问本地系统资源一样,去访问远端系统资源。

RPC

接下来,我们用PHP的socket来简单实现RPC功能:

# Socket服务端

通过Socket来接受RPC客户端来过来的数据,约定发送的数据采用以下数据格式(也可以称为协议):

Rpc-Class:调用的类 Rpc-Method:调用的类中的方法 Rpc-Params: 调用的方法的参数值(数据形式)

RPC

socket服务端代码,模拟远程服务器上的服务:

<?php

class RpcServer {

	private $socket = null;

	function __construct($host, $port, $path) {
		$this->socket = stream_socket_server("tcp://{$host}:{$port}", $errno, $errstr);
		if (!$this->socket) {
			exit("{$errno}:{$errstr} \n");
		}
		// 判断RPC程序目录是否存在
		$realpath = realpath($path);
		if ($realpath === false || !file_exists($realpath)) {
			echo("{$path} error \n");
		}

		while (true) {
			$client = stream_socket_accept($this->socket);
			echo $client." \n";

			if ($client) {
				$buf = fread($client, 2048);
				echo $buf." \n";

				// 解析客户端发过来的协议
				$classRet = preg_match('/Rpc-Class:\s(.*);/i', $buf, $class);
				$methodRet = preg_match('/Rpc-Method:\s(.*);/i', $buf, $method);
				$paramRet = preg_match('/Rpc-Params:\s(.*);/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);

			}
		}
	}

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

new RpcServer('127.0.0.1',8888, './service');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

# Socket客户端

Socket客户端主要是发送socket请求,按照约定数据格式,发送数据:

<?php

class RpcClient {

	private $urlInfo = array();

	function __construct($url) {
		$this->urlInfo = parse_url($url);
		if (!$this->urlInfo) {
			echo("{$url} error \n");
		}
	}

	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->say();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

分别运行server和client代码,运行结果如下:

rpc rpc

这样,通过socket我们就简单实现了RPC的调用。

#PHP#RPC
上次更新: 2022/12/01, 11:09:34
PHP中file_get_contents与curl区别
Protobuf:高效数据结构化工具

← PHP中file_get_contents与curl区别 Protobuf:高效数据结构化工具→

最近更新
01
常用游戏反外挂技术总结
11-27
02
Golang开发实践万字总结
11-11
03
Redis万字总结
10-30
更多文章>
Theme by Vdoing | Copyright © 2011-2022 Ravior | 粤ICP备17060229号-3 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式