类的结构图如下:
数据发送类 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;