Oct
26


作者:Qiu   

  昨天抽空学习了一下XMPP,在网上找了好久,中文的资料太少了所以做这个简单的例子,今天才完成。公司也正在准备开发基于XMPP协议的即时通讯工具所以也算是打一个基础吧!如果你还没有了解过XMPP请先阅读附录中链接的文章,本实例是基agsXMPP上开发的,agsXMPP是C#写的支持开源XMPP协议软件,我们可以在agsXMPP上快速构建自已的即时通讯平台,我的这个例子只是修改了服务器端,因为agsXMPP本身自带的服务器端没有实现聊天功能、签名和登录密码认证。

  服务器端XmppSeverConnection类事件

  //在流开始时触发,一般是最初的响应流

  streamParser.OnStreamStart += new StreamHandler(streamParser_OnStreamStart);

  //在流结束时触发,一般是发送并关闭套接字连接streamParser.OnStreamEnd += new StreamHandler(streamParser_OnStreamEnd);

  //在接收到流结点时触发,这是用得最多的,常用的消息,

  出席消息,请求应答消息都在这里处理

  streamParser.OnStreamElement += new StreamHandler(streamParser_OnStreamElement);

  //此处处理大部份的消息,包括消息路由

  private void streamParser_OnStreamElement(object sender, Node e)

  {

  Console.WriteLine("OnStreamElement: " + e.ToString());

  if (e.GetType() == typeof(Presence))

  {

  // 路由presences节

  }

  else if (e.GetType() == typeof(Message))

  {

  // 路由messages节

  }

  else if (e.GetType() == typeof(IQ))

  {

  //处理IQ节

  }

  }

  ///

  /// IQ节处理函数

  ///

  ///

  .

  private void ProcessIQ(IQ iq)

  {

  if (iq.Query.GetType() == typeof(Auth))

  {

  Auth auth = iq.Query as Auth;

  this.Username = auth.Username.ToString();

  switch (iq.Type)

  {

  case IqType.get:

  iq.SwitchDirection();

  iq.Type = IqType.result;

  auth.AddChild(new Element("password"));

  auth.AddChild(new Element("digest"));

  Send(iq);

  break;

  case IqType.set:

  // 进行登录认证

  if (AccountBus.CheckLogin(auth.Username, auth.Digest, this.SessionId))

  {

  iq.SwitchDirection();

  iq.Type = IqType.result;

  iq.Query = null;

  Send(iq);

  Console.WriteLine(auth.Username + "登录了" + "   登录时间:" + System.DateTime.Now.ToString());

  }

  else

  {

  //登录失败返回错误信息

  iq.SwitchDirection();

  iq.Type = IqType.error;

  iq.Query = null;

  Send(iq);

  }

  break;

  }

  }

  else if (iq.Query.GetType() == typeof(Roster))

  {

  ProcessRosterIQ(iq);

  }

  }

  ///

  /// 处理IQ节的杂项数据.

  ///

  ///

  The iq.

  private void ProcessRosterIQ(IQ iq)

  {

  if (iq.Type == IqType.get)

  {

  // 发送IQ节的杂项数据

  //这里我用来下载好友列表

  iq.SwitchDirection();

  iq.Type = IqType.result;

  Liststring> friendList = new Liststring>();

  friendList = AccountBus.GetFriendName(this.username);

  foreach (string str in friendList)

  {

  RosterItem ri = new RosterItem();

  ri.Name = str.Trim();

  ri.Subscription = SubscriptionType.both;

  ri.Jid = new agsXMPP.Jid(str.Trim() + "@localhost");

  ri.AddGroup("localhost");

  iq.Query.AddChild(ri);

  }

  Send(iq);

  }

  }

  服务器端开启监听5222端口

  while (running)

  {

  ////

  allDone.Reset();

  // Start an asynchronous socket to listen for connections.

  Console.WriteLine("等待连接

  ");

  listener.BeginAccept(new AsyncCallback(AcceptCallback), null);

  //// 等待客户端连接                    

  allDone.WaitOne();

  }

  如果收到客户端请求就异步调用AcceptCallback初始化套接字连接

  ,并为客户端建立一个通信线程,新建初始化套接字连接采用异步调

  用读取套接字信息

  public XmppSeverConnection(Socket sock)

  : this()

  {

  m_Sock = sock;

  m_Sock.BeginReceive(buffer, 0, BUFFERSIZE, 0, new AsyncCallback(ReadCallback), null);

  m_Sock.SendTimeout = 100;

  }

  客户端与服务器端的交互过程

  1客户端异步向服务器端发送连接请求

  2服务器端收到请求,初始化回应流,并随机生成一相SessionID

  8c0" >

  3等待服务器返回消息后客户端发送用户名(由于在客户端采用了异步调用

  方式,所以UI界面感觉不到等待)

  test

  4服务器端收到用户名等待用户提供密码

  test

  5客户端提供加密后的密码

  test

  e66557d2b67256bf7e9b317a51b6101674a56b5e

  MiniClient

  6服务器端从数据库验证用户名和密码,并返回结果

  iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_2" />

  7如果返回错误,客户端提示并终断连接,否则客户端发送响应数据

  8 服务器端返回数据

  9 客户端发送状态,

  10服务器收到状态,发送IQ节并通知其它用户.

  项目解决方案和类图

  

  

您必须登录 才能进行评论。

得到OpenID
使用OpenID提供商
35OpenID 35OpenID MyOpenID MyOpenID Flickr Flickr
Google Google Yahoo Yahoo! AOL AOL
Blogger Blogger LiveJournal LiveJournal Verisign Verisign
ClaimID ClaimID Technorati Technorati Vidoop Vidoop
OpenID OpenID 帮助
您还没有登录,请登录后继续操作。
提示:您必需打开Cookie才能使用本系统
请输入您的 OpenID OpenID 登录:
例如:http://yourname.openid.35.com
close