libjingle学习笔记(1)--从Login example开始

libjingle是gtalk客户端所使用的基础库,主要分为以下几个模块:

base // 一些网络方面的基础库的封装

xmllite // 因为xmpp协议的内容是以xml为基础的,所以这个模块是对xml解析库(expat)的一些封装

xmpp // xmpp协议的实现

p2p // p2p的实现,包括一些nat和firewall穿越的技术

session // gtalk对于声音和文件等的实现

example // 几个例子

 

由于自己以前对于c++网络库了解甚少,所以我打算从例子出发,然后通过例子的程序的前后调用关系将各个类串联起来。

下面是对login example的一个分析:

1. login_main.cc

这个是程序的入口。 主要是开一个子线程(XmppThread)来获得用户输入的信息登录,最后如果输入quit就结束,这边一般主线程结束了子线程也会结束。

int main(int argc, char **argv) {
  printf("Auth Cookie: ");
  fflush(stdout);

  char auth_cookie[256];
  scanf("%s", auth_cookie);
 
  char username[256];
  scanf("%s", username);

  // Start xmpp on a different thread
  XmppThread thread;
  thread.Start();

  buzz::XmppClientSettings xcs;
  xcs.set_user(username);
  xcs.set_host("gmail.com");
  xcs.set_use_tls(false);
  xcs.set_auth_cookie(auth_cookie);
  xcs.set_server(talk_base::SocketAddress("talk.google.com", 5222));
  thread.Login(xcs);

  // Use main thread for console input
  std::string line;
  while (std::getline(std::cin, line)) {
    if (line == "quit")
      break;
  }
  return 0;
}

 

 

XmppThread:

这个类继承了base的Thread,XmppPumpNotify,MessageHandler

class XmppThread:
    public talk_base::Thread, XmppPumpNotify, talk_base::MessageHandler {
public:
  XmppThread();
  ~XmppThread();

  buzz::XmppClient* client() { return pump_->client(); }

  void ProcessMessages(int cms);

  void Login(const buzz::XmppClientSettings & xcs);
  void Disconnect();

private:
  XmppPump* pump_;

 

// implements XmppPumpNotify
  void OnStateChange(buzz::XmppEngine::State state);

 

// implements MessageHandler
  void OnMessage(talk_base::Message* pmsg);
};

#endif // _XMPPTHREAD_H_

 

Thread: 包装了win32 的thread和posix的thread来统一接口。继承自一个MessageQueue, 因此具有循环处理消息的机制,主要函数如下:

bool Thread::ProcessMessages(int cmsLoop) {
  uint32 msEnd;
  if (cmsLoop != kForever)
    msEnd = GetMillisecondCount() + cmsLoop;
  int cmsNext = cmsLoop;

  while (true) {
    Message msg;
    if (!Get(&msg, cmsNext))
      return false;
    Dispatch(&msg);
    
    if (cmsLoop != kForever) {
      uint32 msCur = GetMillisecondCount();
      if (msCur >= msEnd)
        return true;
      cmsNext = msEnd - msCur;
    }
  }
}

用户可以使用Message::Queue继承下来的Post()方法来Post消息到内部的message queue, 然后内部的message queue就Get到这个消息并且Dispatch它。

  virtual void Post(MessageHandler *phandler, uint32 id = 0,
      MessageData *pdata = NULL, bool time_sensitive = false);

这边Post消息的时候需要传入一个messagehandler的指针来处理消息,而dispatch在默认的实现中正是去回调messagehandler的消息处理函数。

 

了解了这些之后我们回到例子,来看看XmppThread的几个函数:

Login和Disconnect等命令函数将消息Post到Thread的message queue,并且制定了handler为this指针。 然后Thread分派消息后XmppThread::OnMessage就对不同消息进行处理,最后委托给XmppPump去完成相应的任务。

void XmppThread::Login(const buzz::XmppClientSettings& xcs) {
  Post(this, MSG_LOGIN, new LoginData(xcs));
}

void XmppThread::Disconnect() {
  Post(this, MSG_DISCONNECT);
}

 

void XmppThread::OnMessage(talk_base::Message* pmsg) {
  if (pmsg->message_id == MSG_LOGIN) {
    assert(pmsg->pdata);
    LoginData* data = reinterpret_cast<LoginData*>(pmsg->pdata);
    pump_->DoLogin(data->xcs, new XmppSocket(false), new XmppAuth());
    delete data;
  } else if (pmsg->message_id == MSG_DISCONNECT) {
    pump_->DoDisconnect();
  } else {
    assert(false);
  }
}

 

 

XmppSocket:

在pump登录的时候创建了一个XmppSocket。XmppSocket主要是对AsyncSocket的一个封装,它将获得当前的Thread,并且在当前Thread的中建立一个AsyncSocket。其实Thread也是一个SocketServer:

class SocketServer : public SocketFactory {
public:

  // Sleeps until:
  //  1) cms milliseconds have elapsed (unless cms == kForever)
  //  2) WakeUp() is called
  // While sleeping, I/O is performed if process_io is true.
  virtual bool Wait(int cms, bool process_io) = 0;

  // Causes the current wait (if one is in progress) to wake up.
  virtual void WakeUp() = 0;
};

} // namespace talk_base

 

socket server是个创建异步socket的factory,并且自己能够不断地去wait()网络异步事件。因为是客户端,所以主要是connected,read,write等网络异步事件。WakeUp是那种致命药丸的概念,即吃一下就停了(挂了)。 当然还有一些singnal/slot机制等,详细的在以后的文章中会解释。

所以XmppSocket类主要是可以写一些回调函数来处理网络异步事件。

 

XmppPump:

这是一个fsm状态机的子类。

在libjingle中最基础的fsm被称为一个Task:

class Task {
 public:
  Task(Task *parent);
  virtual ~Task() {}

  int32 get_unique_id() { return unique_id_; }

  void Start();
  void Step();
  int GetState() const { return state_; }
  bool HasError() const { return (GetState() == STATE_ERROR); }
  bool Blocked() const { return blocked_; }
  bool IsDone() const { return done_; }
  int64 ElapsedTime();

......

 

Task具有父子结构,TaskRunner 也是一个Task,但是他是Task的最原始的父亲

Task::Task(Task *parent)
    : state_(STATE_INIT),
      parent_(parent),
      blocked_(false),
      done_(false),
      aborted_(false),
      busy_(false),
      error_(false),
      child_error_(false),
      start_time_(0),
      timeout_seconds_(0),
      timeout_time_(0),
      timeout_suspended_(false)  {
  children_.reset(new ChildSet());
  runner_ = ((parent == NULL) ?
             reinterpret_cast<TaskRunner *>(this) :
             parent->GetRunner());

......

 

class TaskRunner : public Task, public sigslot::has_slots<> {
 public:
  TaskRunner();
  virtual ~TaskRunner();

  virtual void WakeTasks() = 0;

  // This method returns the current time in 100ns units since 1/1/1601.  This
  // Is the GetSystemTimeAsFileTime method on windows.
  virtual int64 CurrentTime() = 0 ;

  void StartTask(Task *task);
  void RunTasks();
  void PollTasks();

  void UpdateTaskTimeout(Task *task);

  // dummy state machine - never run.
  virtual int ProcessStart() { return STATE_DONE; }
......

 

所以TaskRunner是没有parent的,他的runner是自己,而其他子的Task都是runner都是最顶层的TaskRunner。

 

在这里XmppPump就是一个顶层的TaskRunner,他创建一个XmppClient的Task并且双方加入到父子结构中,而XmppClient的Task就是Xmpp协议的一个实现了,当然需要传入socket和其他一些回调参数。 最后启动Task,将runner wakeup。

void XmppPump::WakeTasks() {
  talk_base::Thread::Current()->Post(this);
}

因为handler为this,所以handle消息启动runner。

void XmppPump::OnMessage(talk_base::Message *pmsg) {
  RunTasks();
}

 

总结:

以上是Login example的基本处理过程,这边主要有以下几个概念:

1. Thread 蕴含一个消息处理机制。

2. Socket事件的异步处理。 Thread是一个SocketServer, 会创建一个Socket,并且对其进行异步网络事件的回调处理。

3. fsm的机制,主要是task和taskRunner的一些概念和关系。

 

后续:

接下来的学习历程会比较深入地解析以上三个概念。 kaka11.chen@gmail.com。希望有兴趣的朋友和我联系,多多学习,呵呵!

 

 

 

 

 

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值