PHP给C++发协议JSON格式(PROTOBUF环境太难配置)

PHP可以直接建立SOCKET连接给C++服务器发协议,省去了解HTTP包头以及维护SESSION的琐碎事情。这两天与GMT对接,他们是直接发的JSON格式过来,我们在PHP里解析并用PROTOBUF格式给C++发协议,但是在配置PHP的PROTOBUF时遇到各种神奇的问题。于是直接用JSON给服务器发协议解决。附上代码:

socket.php:

<?php
class Socket {
	//private:
	var $socket; //socket 句柄
	//var $debug = 1;
	function __construct( $svr_ip,$svr_port) {
		$address = gethostbyname($svr_ip );
		if (($this->socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP))< 0)
		{
			trigger_error("Couldn't create socket:".socket_strerror(socket_last_error())."\n");
		}	
		$result = socket_connect($this->socket,$address,$svr_port );
		socket_set_option($this->socket,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>60, "usec"=>0 ) );
		socket_set_option($this->socket,SOL_SOCKET,SO_SNDTIMEO,array("sec"=>60, "usec"=>0 ) );
	}

	// uniqs send 返回值一个array,第一个参数如果为FALSE表明连接失败
	function usend($msg){
		$send_ret = socket_write($this->socket,$msg, strlen($msg) );
		$buf = socket_read($this->socket,8192);
		$pkg_arr=@unpack("Vproto_len",$buf);
		$proto_len= $pkg_arr["proto_len"];
		//print_r("recv len=".$proto_len);
		while ($proto_len > strlen($buf)) {
			$buf .=	socket_read($this->socket,4096);
		}	
		return array($send_ret, $buf);
	}

	function Close() {
		socket_close($this->socket);
	}

	function __destruct(){
		$this->Close();
	}
} 

?>
BaseProto.php:

<?php
require_once("../common/socket.php");
class BaseProto extends Socket{
	private $head_len = 24;
	private function packMsg($cmdid,$userid,$seqno,$msg){
		global $_SESSION;
		$pkg_len = $this->head_len + strlen($msg);
		$result = 0;
		$sid = 0;
		//return pack("V2v2QV",$pkg_len,$seqno,$cmdid,$sid,$userid,$result).$msg;
		return pack("VvQVvV",$pkg_len,$cmdid,$userid,$result,$sid,$seqno).$msg;
	}

	private function unpackMsgRaw($sockpkg){
		$pkg_head=@unpack("Vlen/vcmdid/Quserid/Vret/vsid/Vseq",$sockpkg);
		$msgstr = substr($sockpkg, $this->head_len);
		return array($pkg_head, $msgstr);
	}

	function sendMsgRaw($cmdid, $userid, $seqno, $req_msg){
		$sendbuf=$this->packMsg($cmdid, $userid, $seqno, $req_msg);
		list($send_ret, $recv_buf) = $this->usend($sendbuf);
		list($ack_head, $ack_msg) = $this->unpackMsgRaw($recv_buf);
		return array($send_ret, $ack_head, $ack_msg);
	}
}

?>
center_proto_raw.php

<?php
require_once("BaseProto.php");

class CenterProtoRaw extends BaseProto {
        function send_raw($param){
                $msgstr = $param;
                SeasLog :: info("send_raw msgstr:" . $msgstr);

                $cmdid = 31000;

                list($send_ret, $ack_head, $ack_msg) = $this->sendMsgRaw($cmdid, 0, 0, $msgstr);
                SeasLog :: info("send_raw ack_msg:" . $ack_msg);

				if($send_ret == FALSE)
				{
					return "send failed check ./config/proto_cfg.xml for detail.";
				}

                return $ack_msg;
        }
}
?>

g.php:

<?php
include "../common/verify.php";
include "../common/util.php";
include "../common/const.php";
require_once("center_proto_raw.php");

$param = file_get_contents("php://input");
$param = urldecode($param);

$json = json_decode($param, true);
$gm_type = (int)$json['gm_type'];

SeasLog :: info("g.php gm_type=" . $gm_type . " param=" . $param);

$doc = new DOMDocument();
$doc->load("config/proto_cfg.xml");
$svrinfo = $doc->getElementsByTagName("Centersvr");
$center_ip = $svrinfo->item(0)->getAttribute("ip");
$center_port = $svrinfo->item(0)->getAttribute("port");

SeasLog :: info("g.php center svr ip=" .$center_ip .", port=" .$center_port);
$centersvr = new CenterProtoRaw($center_ip, $center_port);
$ret_str = $centersvr->send_raw($param);

echo $ret_str;

?>

然后c++里面安装一个jsoncpp解析一下就OK了。

这里顺便吐槽一下rapidjson这个破玩意,号称最快的,参见性能测试: 28个C/C++开源JSON库性能对比 而且还是国人开发的,于是去支持了一把结果发现JSON嵌套一下都解析不了,,,简直是战5渣。。。






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用第三方库,如protobuf-json-util来实现C++JSONProtobuf的功能。个库提供了一些方便的函数和接口,可以帮助你在ProtobufJSON之间进行转换。 首先,你需要在你的C++项目中引入protobuf-json-util库。你可以在GitHub上找到该库的源代码并进行下载和安装。 然后,你需要定义你的Protobuf消息和相应的JSON格式。在Protobuf中,你可以使用.proto文件定义消息结构,在JSON中,你可以使用类似的结构来表示相同的数据。 接下来,你可以使用protobuf-json-util库提供的函数来实现JSONProtobuf的转换。你可以使用`ParseFromJsonString()`函数将JSON字符串解析为Protobuf消息对象,使用`SerializeToJsonString()`函数将Protobuf消息对象序列化为JSON字符串。 下面是一个简单的示例代码: ```cpp #include <iostream> #include <string> #include <protobuf-json-util/json_util.h> #include "your_protobuf_message.pb.h" int main() { // 定义一个Protobuf消息对象 YourProtobufMessage message; // 从JSON字符串解析Protobuf消息对象 std::string json = R"( { "field1": 123, "field2": "hello", "field3": true } )"; json_util::Status status = json_util::ParseFromJsonString(json, &message); if (!status.ok()) { std::cerr << "Failed to parse JSON: " << status.error_message() << std::endl; return 1; } // 将Protobuf消息对象序列化为JSON字符串 std::string serialized_json = json_util::SerializeToJsonString(message); std::cout << "Serialized JSON: " << serialized_json << std::endl; return 0; } ``` 请确保按照protobuf-json-util库的文档进行正确的安装和配置,并根据你的实际需求修改示例代码中的消息类型和字段名。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值