PHP xmlrpc 客户端和 Python 2.5 xmlrpc 服务器:不完整的数据和由对等错误重置的连接

Posted

技术标签:

【中文标题】PHP xmlrpc 客户端和 Python 2.5 xmlrpc 服务器:不完整的数据和由对等错误重置的连接【英文标题】:PHP xmlrpc client and Python 2.5 xmlrpc server: incomplete data and Connection reset by peer error 【发布时间】:2012-03-13 13:30:48 【问题描述】:

我有一个使用 Python 运行的 XML RPC 服务器。

它被实现为 SimpleXMLRPCServer 类的一个实例。

from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler

class MyClass:
    def getGeneExtraInfo(self,genome,infoType,elements):
        print 'DEBUG:\ngenome: %s\ninfoType: %s, elements %s' % (genome,infoType,elements)
        return 'A' * 10000

csfServer = MyClass()

server = SimpleXMLRPCServer((serverHost, serverPort), SimpleXMLRPCRequestHandler)
server.register_instance(csfServer) 
server.serve_forever()

csfServer 具有返回长字符串的方法 def getGeneExtraInfo(self,genome,infoType,elements),为了简单起见,让我们考虑返回 10000 次重复的“A”。

我通过以下代码通过 php 访问此 Web 服务:

function sendRequest($host, $url, $request, $port = 80)                                                                                                                                       

  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  if ($socket === false) 
      echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
      return FALSE;
  

  $address = gethostbyname($host);
  if (!socket_connect ($socket, $address, $port)) 
      echo socket_strerror(socket_last_error());
      return FALSE;
  

  $httpQuery = "POST ". $url ." HTTP/1.0\r\n";
  $httpQuery .= "User-Agent: xmlrpc\r\n";
  $httpQuery .= "Host: ". $host ."\r\n";
  $httpQuery .= "Content-Type: text/xml\r\n";
  $httpQuery .= "Content-Length: ". strlen($request) ."\r\n\r\n";
  $httpQuery .= $request ."\r\n";

  if (!socket_send($socket, $httpQuery , strlen($httpQuery), 0)) 
      echo socket_strerror(socket_last_error());
      return FALSE;
  

  $xmlResponse = "";
  $buff = "";
  while ($bytes = socket_recv($socket, $buff, 1024, MSG_WAITALL) > 0) 
      $xmlResponse .= $buff;
  

  // Just for debugging
  echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($socket)) . "\n";

  socket_close($socket);

  return  $xmlResponse;

$request 变量已构建:

$xmlrpc_output_options = array( 
                        "output_type" => "xml", 
                        "verbosity" => "no_white_space", 
                        "escaping" => array("markup", "non-ascii", "non-print"), 
                        "version" => "xmlrpc", 
                        "encoding" => "UTF-8");


$xmlRequest = xmlrpc_encode_request('getGeneExtraInfo', array($genome,$infoType,$elements), $xmlrpc_output_options);

(可以在下面的 C 和 Python 代码中看到构建的请求)

当服务器运行 python 2.4 时,php 客户端和服务器正常工作,但是 当服务器运行 python 2.5 或 2.6 时,有时(50% 的时间)数据不完整并带有 '对等方错误重置连接。

为了验证问题出在 Python 还是 PHP 上,我编写了两个客户端,一个用 C 语言,另一个用 Python 编写。两者都使用套接字,主要是 PHP 代码的工作方式。 “请求”内容是从 PHP 输出中复制的,这意味着正是对 PHP、C 和 Python 的请求。

C 代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

void error(const char *msg)

        perror(msg);
            exit(0);


int main(int argc, char *argv[])

        int sockfd, n;
        struct sockaddr_in serv_addr;
        struct hostent *server;

        char* hostname=  "wks-13-15";
        int portno = 56572;

        char buffer[1024];

        char request[] = "POST / HTTP/1.0\r\nUser-Agent: xmlrpc\r\nHost: wks-13-15\r\nContent-Type: text/xml\r\nContent-Length: 4479\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodCall><methodName>getGeneExtraInfo</methodName><params><param><value><string>hg19</string></value></param><param><value><string>GO</string></value></param><param><value><array><data><value><string>GO:0044428</string></value><value><string>GO:0044422</string></value><value><string>GO:0044425</string></value><value><string>GO:0044424</string></value><value><string>GO:0043412</string></value><value><string>GO:0006464</string></value><value><string>GO:0009889</string></value><value><string>GO:0003824</string></value><value><string>GO:0016020</string></value><value><string>GO:0016021</string></value><value><string>GO:0048522</string></value><value><string>GO:0048523</string></value><value><string>GO:0090304</string></value><value><string>GO:0019538</string></value><value><string>GO:0051171</string></value><value><string>GO:0001882</string></value><value><string>GO:0001883</string></value><value><string>GO:0080090</string></value><value><string>GO:0042221</string></value><value><string>GO:0048869</string></value><value><string>GO:0019222</string></value><value><string>GO:0005488</string></value><value><string>GO:0005886</string></value><value><string>GO:0005524</string></value><value><string>GO:0031090</string></value><value><string>GO:0050896</string></value><value><string>GO:0010556</string></value><value><string>GO:0010468</string></value><value><string>GO:0016740</string></value><value><string>GO:0003677</string></value><value><string>GO:2000112</string></value><value><string>GO:0005622</string></value><value><string>GO:0019219</string></value><value><string>GO:0006139</string></value><value><string>GO:0032502</string></value><value><string>GO:0032501</string></value><value><string>GO:0050794</string></value><value><string>GO:0009058</string></value><value><string>GO:0032991</string></value><value><string>GO:0044249</string></value><value><string>GO:0044260</string></value><value><string>GO:0044267</string></value><value><string>GO:0035639</string></value><value><string>GO:0009987</string></value><value><string>GO:0044464</string></value><value><string>GO:0051252</string></value><value><string>GO:0043170</string></value><value><string>GO:0005634</string></value><value><string>GO:0005737</string></value><value><string>GO:0050789</string></value><value><string>GO:0031326</string></value><value><string>GO:0051716</string></value><value><string>GO:0016787</string></value><value><string>GO:0031323</string></value><value><string>GO:0006810</string></value><value><string>GO:0048856</string></value><value><string>GO:0065007</string></value><value><string>GO:0043227</string></value><value><string>GO:0043167</string></value><value><string>GO:0044459</string></value><value><string>GO:0043169</string></value><value><string>GO:0008150</string></value><value><string>GO:0008152</string></value><value><string>GO:0006355</string></value><value><string>GO:0005575</string></value><value><string>GO:0046914</string></value><value><string>GO:0003674</string></value><value><string>GO:0006807</string></value><value><string>GO:0003676</string></value><value><string>GO:0044446</string></value><value><string>GO:0044444</string></value><value><string>GO:0051234</string></value><value><string>GO:0032555</string></value><value><string>GO:0043228</string></value><value><string>GO:0043229</string></value><value><string>GO:0043226</string></value><value><string>GO:0045449</string></value><value><string>GO:0032559</string></value><value><string>GO:0031224</string></value><value><string>GO:0017076</string></value><value><string>GO:0071842</string></value><value><string>GO:0071841</string></value><value><string>GO:0071840</string></value><value><string>GO:0060255</string></value><value><string>GO:0016043</string></value><value><string>GO:0034641</string></value><value><string>GO:0008270</string></value><value><string>GO:0000166</string></value><value><string>GO:0046872</string></value><value><string>GO:0044237</string></value><value><string>GO:0044238</string></value><value><string>GO:0043234</string></value><value><string>GO:0043231</string></value><value><string>GO:0043232</string></value><value><string>GO:0032553</string></value><value><string>GO:0005515</string></value><value><string>GO:0007165</string></value><value><string>GO:0048519</string></value><value><string>GO:0048518</string></value><value><string>GO:0030554</string></value></data></array></value></param></params></methodCall>";

        fprintf(stderr, "%s\n", request);

        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) 
            error("ERROR opening socket");
        server = gethostbyname(hostname);

        if (server == NULL) 
            fprintf(stderr,"ERROR, no such host\n");
            exit(0);
        

        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy((char *)server->h_addr, 
                (char *)&serv_addr.sin_addr.s_addr,
                server->h_length);

        serv_addr.sin_port = htons(portno);

        if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
            error("ERROR connecting");

        fprintf(stderr, "%d\n", strlen(request));

        n = write(sockfd,request,strlen(request));
        if (n < 0) 
            error("ERROR writing to socket");

        fprintf(stderr, "%d\n", n);

        bzero(buffer,1024);
        while (read(sockfd,buffer,1023) > 0) 
            printf("%s",buffer);
            bzero(buffer,1024);
        

        if (n < 0) 
            error("ERROR reading from socket");

        close(sockfd);

        return 0;

python代码:

import socket

request = """POST / HTTP/1.0
User-Agent: xmlrpc
Host: wks-13-15
Content-Type: text/xml
Content-Length: 4479

<?xml version="1.0" encoding="UTF-8"?><methodCall><methodName>getGeneExtraInfo</methodName><params><param><value><string>hg19</string></value></param><param><value><string>GO</string></value></param><param><value><array><data><value><string>GO:0044428</string></value><value><string>GO:0044422</string></value><value><string>GO:0044425</string></value><value><string>GO:0044424</string></value><value><string>GO:0043412</string></value><value><string>GO:0006464</string></value><value><string>GO:0009889</string></value><value><string>GO:0003824</string></value><value><string>GO:0016020</string></value><value><string>GO:0016021</string></value><value><string>GO:0048522</string></value><value><string>GO:0048523</string></value><value><string>GO:0090304</string></value><value><string>GO:0019538</string></value><value><string>GO:0051171</string></value><value><string>GO:0001882</string></value><value><string>GO:0001883</string></value><value><string>GO:0080090</string></value><value><string>GO:0042221</string></value><value><string>GO:0048869</string></value><value><string>GO:0019222</string></value><value><string>GO:0005488</string></value><value><string>GO:0005886</string></value><value><string>GO:0005524</string></value><value><string>GO:0031090</string></value><value><string>GO:0050896</string></value><value><string>GO:0010556</string></value><value><string>GO:0010468</string></value><value><string>GO:0016740</string></value><value><string>GO:0003677</string></value><value><string>GO:2000112</string></value><value><string>GO:0005622</string></value><value><string>GO:0019219</string></value><value><string>GO:0006139</string></value><value><string>GO:0032502</string></value><value><string>GO:0032501</string></value><value><string>GO:0050794</string></value><value><string>GO:0009058</string></value><value><string>GO:0032991</string></value><value><string>GO:0044249</string></value><value><string>GO:0044260</string></value><value><string>GO:0044267</string></value><value><string>GO:0035639</string></value><value><string>GO:0009987</string></value><value><string>GO:0044464</string></value><value><string>GO:0051252</string></value><value><string>GO:0043170</string></value><value><string>GO:0005634</string></value><value><string>GO:0005737</string></value><value><string>GO:0050789</string></value><value><string>GO:0031326</string></value><value><string>GO:0051716</string></value><value><string>GO:0016787</string></value><value><string>GO:0031323</string></value><value><string>GO:0006810</string></value><value><string>GO:0048856</string></value><value><string>GO:0065007</string></value><value><string>GO:0043227</string></value><value><string>GO:0043167</string></value><value><string>GO:0044459</string></value><value><string>GO:0043169</string></value><value><string>GO:0008150</string></value><value><string>GO:0008152</string></value><value><string>GO:0006355</string></value><value><string>GO:0005575</string></value><value><string>GO:0046914</string></value><value><string>GO:0003674</string></value><value><string>GO:0006807</string></value><value><string>GO:0003676</string></value><value><string>GO:0044446</string></value><value><string>GO:0044444</string></value><value><string>GO:0051234</string></value><value><string>GO:0032555</string></value><value><string>GO:0043228</string></value><value><string>GO:0043229</string></value><value><string>GO:0043226</string></value><value><string>GO:0045449</string></value><value><string>GO:0032559</string></value><value><string>GO:0031224</string></value><value><string>GO:0017076</string></value><value><string>GO:0071842</string></value><value><string>GO:0071841</string></value><value><string>GO:0071840</string></value><value><string>GO:0060255</string></value><value><string>GO:0016043</string></value><value><string>GO:0034641</string></value><value><string>GO:0008270</string></value><value><string>GO:0000166</string></value><value><string>GO:0046872</string></value><value><string>GO:0044237</string></value><value><string>GO:0044238</string></value><value><string>GO:0043234</string></value><value><string>GO:0043231</string></value><value><string>GO:0043232</string></value><value><string>GO:0032553</string></value><value><string>GO:0005515</string></value><value><string>GO:0007165</string></value><value><string>GO:0048519</string></value><value><string>GO:0048518</string></value><value><string>GO:0030554</string></value></data></array></value></param></params></methodCall>"""

HOST = "wks-13-15"
PORT = 56572

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(request)

while 1:
        data = s.recv(1024)
        print data
        if not data: break

s.close()

两个程序都工作并接收整个响应数据。

我已经尝试更改编码,更改 PHP 读取数据的方式,但数据不完整和 Connection reset by peer 问题仍然存在。

我的问题:(随意回答任何一个问题:-))

为什么 C 和 Python 程序可以工作,而 PHP 有时却不行? 为什么有时 PHP 代码有效,而其他代码无效? 为什么在 python 2.4 上运行的服务器,PHP 客户端代码可以工作,而在 python 2.5 和 2.6 上却不能? 我该如何解决?欢迎提出建议。

【问题讨论】:

尝试在 php 中使用\r\n,您的标题现在不正确。 @Electronick 感谢您的观察,但问题仍然存在。 (我会更新代码示例)。 也许尝试为 fsockopen 更改套接字? “Connection reset by peer”表示你有连接问题(ping?socket写?丢包?) @Electronick 我已经尝试过但没有成功:-( 我建议使用 Wireshark,一个数据包嗅探器,来找出服务器何时重置连接。 【参考方案1】:

我使用xml_rpc 类,我不确定这是从哪个版本的 PHP 开始的,但它适用于我。它甚至会从数组中对您的请求进行编码,但如果您已经有了请求的 XML,我会这样做:

PHP

function sendRequest($host, $url, $request, $port = 80) 

//create the context to send to the xmlrpc server
$context = stream_context_create(array('http' => array(
    'method' => "POST",
    'header' => "Content-Type: text/xml\r\nUser-Agent: PHPRPC/1.0\r\n",
    'content' => $request
)));

//i am not sure how to get the url, normally something like http://server/api/xml
$server = "http://$host:$port"; //?

//store the response
$file = file_get_contents($server, false, $context);
//decode the response to xml
$return xmlrpc_decode($file);

【讨论】:

我更新以模仿你的功能,我不确定你的服务器 url 是什么样子,只是看一眼我看到你正在解码主机名的代码,这样你就可以弄清楚如何指向 @ 987654323@ url 到您的主机,但这适用于我曾经尝试使用 PHP 发出的每个 xmlrpc 请求。

以上是关于PHP xmlrpc 客户端和 Python 2.5 xmlrpc 服务器:不完整的数据和由对等错误重置的连接的主要内容,如果未能解决你的问题,请参考以下文章

Python 的 xmlrpc 非常慢:每次调用一秒钟

10 分钟入门 python rpc 实现

Qt(PyQt)事件循环中的xmlrpc?

使用 XMLRPC 将文件从客户端发送到服务器?

需要 PHP5 的示例 XML-RPC 客户端代码 [关闭]

python xmlrpc