xmlrpc笔记

来源:互联网 发布:2016淘宝手机店铺装修 编辑:程序博客网 时间:2024/05/21 07:50

类的结构图如下:

数据发送类 XmlRpcDispatch

client,server都用使用此类发送数据。

客户端 XmlRpcClient

构造函数为:

 XmlRpcClient(const char* host, int port, const char* uri=0);//参数1为IP,参数2为端口。

execute():  bool execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result);

解释如下:

    //! Execute the named procedure on the remote server
    //!  @param method The name of the remote procedure to execute
    //!  @param params An array of the arguments for the method
    //!  @param result The result value to be returned to the client
    //!  @return true if the request was sent and a result received

close():

解释如下:

//! Close the connection

源码解释

bool  XmlRpcClient::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result)
{
  XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s (_connectionState %d).", method, _connectionState);

  // This is not a thread-safe operation, if you want to do multithreading, use separate
  // clients for each thread. If you want to protect yourself from multiple threads
  // accessing the same client, replace this code with a real mutex.
  if (_executing)
    return false;

  _executing = true;
  ClearFlagOnExit cf(_executing);

  _sendAttempts = 0;
  _isFault = false;

  if ( ! setupConnection()) //创建SOCKET进行连接 

    return false;

  if ( ! generateRequest(method, params)) // 打包数据
    return false;

  result.clear();
  double msTime = -1.0;   // Process until exit is called
  _disp.work(msTime);  //发送请求,接收回复的内容

  if (_connectionState != IDLE || ! parseResponse(result)) //解析回复的内容
    return false;

  XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s completed.", method);
  _response = "";
  return true;
}

void  XmlRpcDispatch::work(double timeout)   //客户端跟server端都会调用此函数。
{
  // Compute end time
  _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout);
  _doClear = false;
  _inWork = true;

  // Only work while there is something to monitor
  while (_sources.size() > 0) {

    // Construct the sets of descriptors we are interested in
    fd_set inFd, outFd, excFd;
   FD_ZERO(&inFd);
   FD_ZERO(&outFd);
   FD_ZERO(&excFd);

    int maxFd = -1;     // Not used on windows
    SourceList::iterator it;
    for (it=_sources.begin(); it!=_sources.end(); ++it) {
      int fd = it->getSource()->getfd();\
      if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
      if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
      if (it->getMask() & Exception)     FD_SET(fd, &excFd);
      if (it->getMask() && fd > maxFd)   maxFd = fd;
    }

    // Check for events
    int nEvents;
    if (timeout < 0.0)
      nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
    else
    {
      struct timeval tv;
      tv.tv_sec = (int)floor(timeout);
      tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
      nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
    }

    if (nEvents < 0)
    {
      XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
      _inWork = false;
      return;
    }

    // Process events
    for (it=_sources.begin(); it != _sources.end(); )     客户端会在 for (it=_sources.begin(); it != _sources.end(); )退出,服务端不会。
    {
      SourceList::iterator thisIt = it++;
      XmlRpcSource* src = thisIt->getSource();
      int fd = src->getfd();
      unsigned newMask = (unsigned) -1;
      if (fd <= maxFd) {
        // If you select on multiple event types this could be ambiguous
        if (FD_ISSET(fd, &inFd))
          newMask &= src->handleEvent(ReadableEvent);
        if (FD_ISSET(fd, &outFd))
          newMask &= src->handleEvent(WritableEvent);   //处理需要发送的请求,并接收回复的内容。
        if (FD_ISSET(fd, &excFd))
          newMask &= src->handleEvent(Exception); 

        if ( ! newMask) {
          _sources.erase(thisIt);  // Stop monitoring this one,一删除,就会退出循环。
          if ( ! src->getKeepOpen())
            src->close();
        } else if (newMask != (unsigned) -1) {
          thisIt->getMask() = newMask;  // 
        }
      }
    }

    // Check whether to clear all sources
    if (_doClear)
    {
      SourceList closeList = _sources;
      _sources.clear();
      for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
  XmlRpcSource *src = it->getSource();
        src->close();
      }

      _doClear = false;
    }

    // Check whether end time has passed
    if (0 <= _endTime && getTime() > _endTime)
 {

      break;
 }
  }

  _inWork = false;
}

 

unsigned
XmlRpcClient::handleEvent(unsigned eventType)
{
xxx

  if (_connectionState == WRITE_REQUEST)
    if ( ! writeRequest()) return 0;                                //发送请求

  if (_connectionState == READ_HEADER)
    if ( ! readHeader()) return 0;                                 //从收到的内容去掉头

  if (_connectionState == READ_RESPONSE)
    if ( ! readResponse()) return 0;                          //没收完,接着收,返回0,导致_sources.erase(thisIt);接着循环退出。

 xxx

}

服务端 XmlRpcServer

服务器运行的例子如下:

XmlRpcServer s;

 XmlRpc::setVerbosity(5);   //设置日志级别

 // Create the server socket on the specified port
 s.bindAndListen(Transmit_xmlrpc_port); //创建SOCKET(非阻塞,端口复用),开始绑定监听。

 // Enable introspection
 s.enableIntrospection(true);

 // Wait for requests indefinitely
 s.work(-1.0); // 

xmlrpc 方法的例子如下:

// xmlrpc method
class xxxxxmethod: public XmlRpcServerMethod
{
public:
 xxxxxmethod(XmlRpcServer* s) : XmlRpcServerMethod("xxxx", s) {}

 void execute(XmlRpcValue& params, XmlRpcValue& result)
 {   //   }

} OpenVodFile(&s);

 

 XmlRpcServer 会有一个 typedef std::map< std::string, XmlRpcServerMethod* > MethodMap的成员MethodMap _methods,每个xmlrpc method在构造的时候,都会添加到_methods中, 如下:

  XmlRpcServerMethod::XmlRpcServerMethod(std::string const& name, XmlRpcServer* server)
  {
    _name = name;
    _server = server;
    if (_server) _server->addMethod(this);
  }

源码解释:

 Server端采用select模型,

void  XmlRpcDispatch::work(double timeout)

{

xxx

while (_sources.size() > 0) {

     int  nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);  //无限等待。
xxx

 _sources.erase(thisIt);  //客户端的socket在close后,服务端的select会检测到,但收不到数据,最终导致被删除。

}

XmlRpcDispatch::clear()  //清除链表 SourceList closeList的内容。 

XmlRpcDispatch::exit()   //将会使server端的XmlRpcDispatch::work(double timeout)退出循环。
XmlRpcDispatch::addSource,XmlRpcDispatch::removeSource,XmlRpcDispatch::setSourceEvents,均是处理链表 SourceList closeList。

unsigned XmlRpcServerConnection::handleEvent(unsigned /*eventType*/)
{
  if (_connectionState == READ_HEADER)
    if ( ! readHeader()) return 0;        //读头

  if (_connectionState == READ_REQUEST)
    if ( ! readRequest()) return 0;    //分析请求

  if (_connectionState == WRITE_RESPONSE)
    if ( ! writeResponse()) return 0;    //处理,并回复

  return (_connectionState == WRITE_RESPONSE)
        ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
}

问题

1.用的MD库,WIN7系统,端口用12580,有的命令C收成功,有的命令,C收失败?

2.网上的xmlrpc的资料都是关于WEB的?

3.

XmlRpcServer::XmlRpcServer()
{
  _introspectionEnabled = false;
  _listMethods = 0;
  _methodHelp = 0;
}


XmlRpcServer::~XmlRpcServer()
{
  this->shutdown();
  _methods.clear();
  delete _listMethods;
  delete _methodHelp;
}

void XmlRpcServer::enableIntrospection(bool enabled)
{
  if (_introspectionEnabled == enabled)
    return;

  _introspectionEnabled = enabled;

  if (enabled)
  {
    if ( ! _listMethods)
    {
      _listMethods = new ListMethods(this);
      _methodHelp = new MethodHelp(this);
    } else {
      addMethod(_listMethods);
      addMethod(_methodHelp);
    }
  }
  else
  {
    removeMethod(LIST_METHODS);
    removeMethod(METHOD_HELP);
  }
}

如上,如果enableIntrospection(false),析构函数的delete _listMethods就会报错,改为if(_listMethods)delete _listMethods;