Rumah  >  Artikel  >  php教程  >  用C++ ulxmlrpcpp 做服务端,PHP xmlrpc 做客户端,实现前后xml

用C++ ulxmlrpcpp 做服务端,PHP xmlrpc 做客户端,实现前后xml

WBOY
WBOYasal
2016-06-06 19:59:261415semak imbas

前一阵,想在fedora下用C服务程序,PHP前台程序,实现一个系统。选择封装完整HTTP协议通信,且实现多线程的程序库:ulxmlrpcpp。但是这个库只封装c的客户端和服务端,所以决定在客户端使用PHP xml-rpc。然而两个库并不能完全通信,需要修改一些源码(只修改u

前一阵,想在fedora下用C++服务程序,PHP前台程序,实现一个系统。选择封装完整HTTP协议通信,且实现多线程的程序库:ulxmlrpcpp。但是这个库只封装c++的客户端和服务端,所以决定在客户端使用PHP xml-rpc。然而两个库并不能完全通信,需要修改一些源码(只修改ulxmlrpcpp代码,所以需要重新编译ulxmlrpcpp,而phpxmlrpc不需要修改)。

1.程序下载:(linux)

ulxmlrpcpp-1.7.5:http://download.csdn.net/detail/liuzhengjian123/4497109

expat-2.1.0:http://download.csdn.net/detail/liuzhengjian123/4497115

phpxmlrpc-3.0.0:http://download.csdn.net/detail/liuzhengjian123/4497119

2.程序安装:(linux)

ulxmlrpcpp和expat的安装都是使用命令:

./confingure

make

make install

注意:安装ulxmlrpcpp前需要先安装expat,还要修改部分代码(详细参考后面)。

phpxmlrpc无需安装,只要将lib目录下的三个文件xmlrpc.inc、xmlrpcs.inc和xmlrpc_wrappers.inc放到php包含目录下即可。如果只编写客户端程序,那么只需要xmlrpc.inc就够了。

3.ulxmlrpcpp代码修改:

1)ulxr_config.h文件:添加如下宏定义,或注释部分宏

#define ULXR_VERSION "1.7.5"
#define ULXR_DATADIR "./"
//#define ULXR_UNICODE 1
2)ulxmlrpcpp.h文件:取消下面宏定义的注释
#define ULXR_ENFORCE_NON_PERSISTENT
3)ulxr_http_protocol.cpp文件:注释掉573和574行
//else
    //setPersistent(true);
4.修改原因

1.修改之前可能会根本无法通信,首先要编写好ulxmlrpcpp后台程序,添加调用函数。编写PHP前台程序,注意调用相应的函数,主机名 和端口:ulxmlrpcpp配置文件如下:

# IP for xmlrpc server
xmlrpc_ip = localhost
# Port for xmlrpc server
xmlrpc_port = 32005
wbxml = 0
ssl = 0
secure = 0
chunked = 0
shutdown = 0
persistent = 0
代码调试成功后可能还是无法通信的原因可能是SELinux的问题,前台会提示错误信息:
(13)Permission denied
这个是SELinux的访问控制权限的问题,执行下面命令就可以解决:
# setsebool -P httpd_can_network_connect 1

2.代码调试正确之后,可能会出现服务端可以收到调用请求,但是而且回答也正常发送,但是前台PHP无法解析回答的xml,而求PHP页面一直在等待,超时后才结束。错误代码:

Code: 2 Reason: 'Invalid return payload: enable debugging to examine incoming payload (XML error: Invalid document end at line 2, column 1)'
而且打开PHP调试信息函数:$c->setDebug(1); 会发现PHP页面会显示收到两个http回复包:
---GOT---
HTTP/1.1 200 OK ------------------(第一个回复包,看上去正常)
Proxy-Connection: Keep-Alive
Content-Type: text/xml
Content-Length: 130
X-Powered-By: ulxmlrpcpp/1.7.5
Server: localhost
Date: Mon Aug 13 20:15:57 2012

<?xml version="1.0" encoding="utf-8"?><methodresponse><params><param><value><i4>23</i4></value></params></methodresponse>
HTTP/1.1 200 OK  --------------------(第二个回复包,超时错误提示)
Connection: Keep-Alive
Content-Type: text/xml
Content-Length: 306
X-Powered-By: ulxmlrpcpp/1.7.5
Server: localhost
Date: Mon Aug 13 20:16:07 2012

<?xml version="1.0" encoding="utf-8"?><methodresponse><fault><value><struct><member><name>faultCode</name><value><i4>500</i4></value></member><member><name>faultString</name><value><string>Timeout while attempting to read (using select).</string></value></member></struct></value></fault></methodresponse>
---END---
为什么会返回两个包呢,经过分析,服务端采用了连续通信方式,发送回复包后,并不断开TCP连接,一直等待前台回复,而前台PHP端并没有采用这种策略,并不会再次向客户端请求断开。所以服务端一直等到超时才主动断开连接,断开连接还向前台发送了一个超时错误提示的包(就是第二个包)。所以我们要让后台ulxmlrpcpp发送回复后就断开连接,及采用不连续的方式,所以要修改上面标题3 中的 2)和3),使其强制断开。

5.代码:

1)前台php示例代码:client.php

<title>xmlrpc</title>

<h1>Getstatename demo</h1>
<h2>Send a U.S. state number to the server and get back the state name</h2>
<h3>The code demonstrates usage of the php_xmlrpc_encode function</h3>
<?php include("xmlrpc.inc");

	// Play nice to PHP 5 installations with REGISTER_LONG_ARRAYS off
	if(!isset($HTTP_POST_VARS) && isset($_POST))
	{
		$HTTP_POST_VARS = $_POST;
	}
	if(isset($HTTP_POST_VARS["stateno"]) && $HTTP_POST_VARS["stateno"]!="")
	{
		$stateno=(integer)$HTTP_POST_VARS["stateno"];
		$f=new xmlrpcmsg('testcall_in_class_dynamic',
			array(php_xmlrpc_encode($stateno))
		);
		print "<pre class="brush:php;toolbar:false">Sending the following request:\n\n" . htmlentities($f->serialize()) . "\n\nDebug info of server data follows...\n\n";
		$c=new xmlrpc_client("./RPC2", "localhost", 32005);
		$c->setDebug(1);
		$r=&$c->send($f);
		echo htmlentities($r->serialize());
		
		if(!$r->faultCode())
		{
			$v=$r->value();
			print "

State number " . $stateno . " is " . htmlspecialchars($v->scalarval()) . "
"; // print "
I got this value back
" .
			//  htmlentities($r->serialize()). "

\n"; } else { print "An error occurred: "; print "Code: " . htmlspecialchars($r->faultCode()) . " Reason: '" . htmlspecialchars($r->faultString()) . "'
"; } } else { $stateno = ""; } print "

Enter a state number to query its name

"; ?>
$Id: client.php 2 2009-03-16 20:22:51Z ggiunta $ 2)后台C++示例代码:server.cpp
#include <ulxmlrpcpp>  // always first header

#include <cstring>
#include <cstdlib>

#include <ulxmlrpcpp>  // first, don't move: msvc #include bug
#include <ulxmlrpcpp>
#include <ulxmlrpcpp>

#ifdef __WIN32__
#include <process.h>
#endif

#include "util.c"

#ifdef ULXR_MULTITHREADED

#ifdef __unix__
#include <pthread.h>
#endif

#endif

#include <iostream>
#include <cstring>
#include <memory>

#include <ulxmlrpcpp>
#include <ulxmlrpcpp>
#include <ulxmlrpcpp>


#ifdef __WIN32__
const unsigned num_threads = 10;
#else
const unsigned num_threads = 100;
#endif

////////////////////////////////////////////////////////////////////////

#ifdef ULXR_MULTITHREADED

ulxr::MultiThreadRpcServer *mtServer = 0;

class TestWorker
{
 public:

   TestWorker ()
   {
   }

   ulxr::MethodResponse numThreads (const ulxr::MethodCall &/*calldata*/)
   {
     ulxr::MethodResponse resp;
     resp.setResult(ulxr::Integer(mtServer->numThreads()));
     return resp;
   }

   ulxr::MethodResponse shutdown (const ulxr::MethodCall &/*calldata*/)
   {
     ULXR_COUT terminateAllThreads();
     ULXR_COUT send(ULXR_PCHAR("DEBUG"),
                              ULXR_PCHAR("mt_server started"),
                              ULXR_GET_STRING(__FILE__),
                              __LINE__);

    ulxr::CppString host = ULXR_PCHAR("localhost");
    if (argc > 1)
      host = ULXR_GET_STRING(argv[1]);

    unsigned port = 32005;
    if (argc > 2)
      port = ulxr_atoi(argv[2]);

    bool wbxml = haveOption(argc, argv, "wbxml");
    bool secure = haveOption(argc, argv, "ssl");
    bool chunked = haveOption(argc, argv, "chunked");
    bool shutme = haveOption(argc, argv, "shutdown");
    bool persistent = haveOption(argc, argv, "persistent");

    ulxr::CppString sec = ULXR_PCHAR("unsecured");
    if (secure)
      sec = ULXR_PCHAR("secured");

    ULXR_COUT  conn;
#ifdef ULXR_INCLUDE_SSL_STUFF
    if (secure)
    {
      ulxr::SSLConnection *ssl = new ulxr::SSLConnection (true, host, port);
      ssl->setCryptographyData("password", "foo-cert.pem", "foo-cert.pem");
      conn.reset(ssl);
    }
    else
#endif
#ifdef _MSC_VER
  {
      std::auto_ptr<:tcpipconnection> temp(new ulxr::TcpIpConnection (true, host, port));
    conn = temp;
    }
#else
      conn.reset(new ulxr::TcpIpConnection (true, host, port));
#endif

    std::auto_ptr<:httpprotocol> prot(new ulxr::HttpProtocol(conn.get()));
    prot->setChunkedTransfer(chunked);
    prot->setPersistent(persistent);
    if (persistent)
      conn->setTcpNoDelay(true);

    if (prot->isPersistent())
      ULXR_COUT 6.总结

<p><span><span>本文重点就是第3点的代码修改,虽然需要修改的地方并不是很多,但是也让我花了好长时间去分析ulxmlrpcpp源代码,才找出错误原因的,希望能给大家带来一些帮助。</span></span></p>


<p><span></span></p>
<p><span><br>
</span></p>
<p><span><br>
</span></p>
<p></p>


</:httpprotocol></:tcpipconnection></ulxmlrpcpp></ulxmlrpcpp></ulxmlrpcpp></memory></cstring></iostream></pthread.h></process.h></ulxmlrpcpp></ulxmlrpcpp></ulxmlrpcpp></cstdlib></cstring></ulxmlrpcpp>
Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel sebelumnya:利用php搭建oauthArtikel seterusnya:PHP Manager for IIS