.net平台 基于 XMPP协议的即时消息服务端简单实现 (转)

it2025-03-17  15

 

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

// 在流开始时触发,一般是最初的响应流 streamParser.OnStreamStart  +=   new  StreamHandler(streamParser_OnStreamStart); // 在流结束时触发,一般是发送</stream:stream>并关闭套接字连接streamParser.OnStreamEnd += new StreamHandler(streamParser_OnStreamEnd); // 在接收到流结点时触发,这是用得最多的,常用的<message>消息,<Presence>出席消息,< IQ>请求应答消息都在这里处理 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节             }         }

 

  ///   <summary>          ///  IQ节处理函数          ///   </summary>          ///   <param name="iq"> . </param>          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);             }         }

 

///   <summary>          ///  处理IQ节的杂项数据.          ///   </summary>          ///   <param name="iq"> The iq. </param>          private   void  ProcessRosterIQ(IQ iq)         {              if  (iq.Type  ==  IqType. get )             {                  //  发送IQ节的杂项数据                // 这里我用来下载好友列表                 iq.SwitchDirection();                 iq.Type  =  IqType.result;                 List < string >  friendList  =   new  List < string > ();                 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客户端异步向服务器端发送连接请求

<stream:stream to='localhost' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>

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

 <stream:stream xmlns:stream="http://etherx.jabber.org/streams" from="localhost" id="30e3b8c0" >

3等待服务器返回消息后客户端发送用户名(由于在客户端采用了异步调用 方式,所以UI界面感觉不到等待)

<iq xmlns="jabber:client" id="agsXMPP_1" type="get" to="localhost"> <query xmlns="jabber:iq:auth"><username>test</username></query></iq>

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

<iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_1"> <query xmlns="jabber:iq:auth"><username>test</username><password /> <digest /></query></iq>

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

<iq xmlns="jabber:client" id="agsXMPP_2" to="localhost" type="set"> <query xmlns="jabber:iq:auth"><username>test</username> <digest>e66557d2b67256bf7e9b317a51b6101674a56b5e</digest> <resource>MiniClient</resource></query></iq>

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

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

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

8 服务器端返回数据

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

项目解决方案和类图 附录:推荐使用Pandion作为客户端服务器端下载      客户端下载agsXMPP 源码下载 XMPP RFC 3920 可扩展消息出席协议 jabber官方网站

转载于:https://www.cnblogs.com/HappyQQ/archive/2008/01/12/1036582.html

相关资源:数据结构—成绩单生成器
最新回复(0)