基于 XMPP协议的即时消息服务端简单实现

服务器端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节并通知其它用户.

项目解决方案和类图

基于 XMPP协议的即时消息服务端简单实现_第1张图片
附录:
推荐使用Spark作为客户端

你可能感兴趣的:(基于 XMPP协议的即时消息服务端简单实现)