P2psim源代码分析四

来源:互联网 发布:win10 正在准备windows 编辑:程序博客网 时间:2024/05/18 00:59

P2psim源代码分析四

Kejieleung

 

ChannelRPC

这次重点分析ChannelRPCChannel作为底层task的数据通道,用于传输task之间的数据。channel结点定义为(注意在定义task.h,还有相关的操作)

struct Channel

{

      unsigned int               bufsize;

      unsigned int               elemsize;

      unsigned char            *buf;

      unsigned int               nbuf;

      unsigned int               off;

      Altarray asend;

      Altarray arecv;

      char                     *name;

};

PacketRPCHandleNetworkEventQueue里都有使用到.

EventQueue的构造函数如下:

EventQueue::EventQueue() : _time(0)

{

 

//kejie: Channel *_gochan;

  _gochan = chancreate(sizeof(Event*), 0);

  assert(_gochan);

 

//kejie:add self run to the threadmanage

  thread();

}

之后再通过EventQueue::run()线程函数时调用 recvp(_gochan) 接收底层task发送到channel的数据。详细的实现可以进一步看看task里的定义,不过反正这部分不是重点,只要了解一下就可以。

   一般意义的RPC使用client/server模型。请求程序是client,而服务提供程序则为server。就像一般的本地过程调用一样,且RPC是一个同步操作,直到远程过程结果返回请求程序才可以挂起。P2PSim里的RPC机制在是单机里的模拟。通过底层的channel来传递请求。先看看RPCHandle的定义:

class RPCHandle { public:

  RPCHandle(Channel*, Packet*);

  ~RPCHandle();

 

  Channel *channel() { return _c; }

  Packet *packet() { return _p; }

 

private:

  Channel* _c;

  Packet* _p;

 

};

定义很简单,主要是看用法和相关操作,集中在Node.h里使用,且多数操作是以模板形式,还用到了成员函数指针,所以看起来比较费劲呵呵,不过没关系,慢慢来。关于Node类的详细分析留在下一章进行,这里先抽出RPC相关操作与数据结构。

相关操作有:

// Send an RPC from a Node on one Node to a method

// of the same Node sub-class with a different ip

template<class BT, class AT, class RT>

 bool doRPC(IPAddress dst, void (BT::* fn)(AT *, RT *), AT *args, RT *ret, Time timeout = 0)

 

// Same as doRPC, but this one is asynchronous

template<class BT, class AT, class RT>

unsigned asyncRPC(IPAddress dst,

  void (BT::* fn)(AT *, RT *), AT *args, RT *ret, Time timeout = 0, unsigned token = 0)

        

// returns one of the RPCHandle's for which a reply has arrived. BLOCKING.( Used in asyncRPC)

unsigned rcvRPC(RPCSet*, bool&);

 

void _deleteRPC(unsigned);

 

typedef set<unsigned> RPCSet;

HashMap<unsigned, RPCHandle*> _rpcmap;

 

 

// RPC machinery

template<class BT, class AT, class RT>

class Thunk

 

bool _doRPC(IPAddress, void (*fn)(void *), void *args, Time timeout = 0);

 

RPCHandle* _doRPC_send(IPAddress, void (*)(void *), void (*)(void*), void *, Time = 0);

bool _doRPC_receive(RPCHandle*);           

 

// creates a Thunk object with the necessary croft for an RPC

//kejie:  Node::Thunk<BT, AT, RT> * 为返回值

template<class BT, class AT, class RT>

Node::Thunk<BT, AT, RT> *

  _makeThunk(IPAddress dst, BT *target, void (BT::*fn)(AT*, RT*),AT *args, RT *ret)

 

具体的实现都在Node.h里,由于部分模板函数比较复杂,等到具体协议实现时再回过头来分析,这里先放一下,只分析一下recvRPC析流程。

recvRPC用于返回一个已有回应到达的RPCHandle,注释里说是一个阻塞操作,理解为有立即返回结果即可:

(1)   根据hset里标识的索引,在_rpcmap里找出要接收信息的channel信息,记录在Alt数组里

Alt定义为(task.h)

struct Alt

{

       Channel               *c;

       void                            *v;

       unsigned int        op;

       Task                            *task;

       Alt                        *xalt;

};

注意还有一个alt是定义为

#define  alt          chanalt

int          chanalt(Alt *alts);

(2)   传入alt(a)->[ chanalt(Alt*a) ] 处理执行

(3)   alt中,首先要确定传入的alt的长度,设定为taskrunning

(4)   检查每个a[i]是否可运行,记录可运行的数目,如果多于一个就随机选择一个

(5)   确认是否有数据返回,再删除索引

详细代码如下:

 

 

整体的RPC操作可以参考以下UML图,再对照源代码:

(由于暂时上传不了图片,以后再补上)

也可以留下E-mail我将word版本传过去哈~~~最好直接发到我的邮箱因为有时没上空间也不知道呢呵呵~~

kejieleung@163.com