如何实现一个IM

如何实现一个IM

Client + Data Transfer Protocol + Server 搞定这三个部分就能实现一个IM

  • Client: 根据支持PC、浏览器、手机等特性来决定支持的语言来实现

  • Transfer Protocol: http/tcp(ip)/)websocket + xml/json 来实现

  • Server: 主要承担Client信息记录、连接管理、信息路由等职责

  • Getway: 网关是用来实现异构IM互通,主要用于协议转换和交互. 可选.

IM常用功能

  • 即时通讯 - 在用户和在线朋友之间来回发送信息
  • 聊天 - 创建用户与朋友的自定义聊天室
  • 网页链接 - 共享用户喜爱的网址
  • 支持图片 - 浏览朋友计算机中的图片
  • 支持声音 - 给朋友播放音乐
  • 支持文件传输 - 直接将文件发送给朋友,以便于共享
  • 交谈 - 使用 Internet,而不是电话,与朋友们进行真正的交谈
  • 影音串流内容 - 实时或准实时的股市行情或新闻

数据传输协议选择 - XMPP

我们简要说明一下XMPP协议

Xmpp协议 —— 简单说来就是基于XML的一种实时通信协议,包含打包、解包消息,一般使用tcp/ip通讯。

优缺点

  • 优点: 扩展性好
  • 缺点:XML冗余数据多,另外Xmpp协议定义的交互方式导致完成一次会话交互次数比较多,造成数据流量浪费;且不能修改二进制的问题,所以文件传输只能使用外部Http

JID(Jabber Identifier, JID)

Xmpp协议中定义的各种对象和实体(用户、Server、Gateway)都可以用唯一的JID标识,成为Jabber地址. 具体格式:

[ node "@" ] domain [ "/" resource ]

最常见的标识一个用户,比如:joseph@imserver/ipad .resource用来标识用户的特殊对象,比如位置或设备

XML数据结构

<stream>
--------------------------
	<presence></presence> 
--------------------------
	<message></message>
--------------------------
	<iq></iq> 
--------------------------
<stream>    

每一条线分割标识一次会话

要区分两个基本概念:XML流和XML节

  • XML流是整个网络交互的容器,包含了所有网络交互的XML元素,XMPP是以开头,结尾关闭流. 这是异步数据传输的一种标准方式.

  • XML节是通过XML流传输的一种结构化信息单元,比如<presence/>、<message/>、<iq/>

  • 比较特殊的是安全认证相关的元素,不被认为是XML节,主要用于协商传输层安全协议、简单认证与安全层协议和服务器回拨认证协议完成通信认证、加密等目的的数据交互

流元素属性
属性 初始方->接收方 接收方->初始方
to 接收方的主机名 忽略
from 忽略 接收方的主机名
id 忽略 会话键值
xml:lang 缺省语言 缺省语言
version 支持XMPP1.0 支持XMPP1.0

交互过程

SENT (0): <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
RECV (0): <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="96fafe03" xml:lang="en" version="1.0"><stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/><register xmlns="http://jabber.org/features/iq-register"/></stream:features>
SENT (0): <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'>=</auth>
RECV (0): <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cmVhbG09IjEyNy4wLjAuMSIsbm9uY2U9Illuc1Z4U2VyY2RSZVF2WTFSdlVTd21OSUdZVk50N2pNb2MwNG1WenAiLHFvcD0iYXV0aCIsY2hhcnNldD11dGYtOCxhbGdvcml0aG09bWQ1LXNlc3M=</challenge>
SENT (0): <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>Y2hhcnNldD11dGYtOCx1c2VybmFtZT0idGVzdFVzZXIxIixyZWFsbT0iMTI3LjAuMC4xIixub25jZT0iWW5zVnhTZXJjZFJlUXZZMVJ2VVN3bU5JR1lWTnQ3ak1vYzA0bVZ6cCIsbmM9MDAwMDAwMDEsY25vbmNlPSJpL0FSanM3MWFXeXJlN2xhY3hSQ2NtVDROTVNlRXd1ay9hUUtwT3k4IixkaWdlc3QtdXJpPSJ4bXBwLzEyNy4wLjAuMSIsbWF4YnVmPTY1NTM2LHJlc3BvbnNlPWQ3NjZjMmZlZWY3YjI0ZWZmODMyYTdlY2ZiNWU1YzgyLHFvcD1hdXRo</response>
RECV (0): <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cnNwYXV0aD1kN2IxZjQzNWI4ODEwZDVkZTc0NmNjMzcwYmUzMGRjOQ==</success>
SENT (0): <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='96fafe03' xml:lang='en'>
RECV (0): <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="96fafe03" xml:lang="en" version="1.0"><stream:features><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>
SENT (0): <iq id='bBkWS-1' type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>Smack</resource></bind></iq>
RECV (0): <iq type="result" id="bBkWS-1" to="127.0.0.1/96fafe03"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>testuser1@127.0.0.1/Smack</jid></bind></iq>
SENT (0): <iq id='bBkWS-3' type='set'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>
RECV (0): <iq type="result" id="bBkWS-3" to="testuser1@127.0.0.1/Smack"/>
User logged (0): testuser1@127.0.0.1:5222/Smack
XMPPConnection authenticated (0)
SENT (0):<iq id='bBkWS-5' type='get'><query xmlns='jabber:iq:roster'></query></iq>
SENT (0): <presence id='bBkWS-6'></presence>
RECV (0): <iq type="result" id="bBkWS-5" to="testuser1@127.0.0.1/Smack"><query xmlns="jabber:iq:roster"/></iq>
RECV (0): <presence id="bBkWS-6" from="testuser1@127.0.0.1/Smack" to="testuser1@127.0.0.1/Smack"/>
SmackClient.(68) - testUser1 login successful.
SENT (0): <message to='testUser2@127.0.0.1' id='bBkWS-9' type='chat'><body>hello,too.</body><thread>090684cf-ba64-4c9b-a03d-edad92dc4ea6</thread></message>
SmackClient.(159) - 向[testUser2]发送消息[hello,too.]

安全

TSL(传输层安全协议)

XMPP 为防止篡改和偷听.TLS加密方法, 模拟了类似的其他"STARTTLS" 的扩展,如 IMAP [IMAP], POP3 [POP3]"STARTTLS"。扩展命名空间是'urn:ietf:params:xml:ns:xmpp-tls'.

STARTTLS 是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL),而不是另外使用一个端口作加密通信。

交互过程:客户端先询问服务端是否支持TSL/SSL,如果服务端回复支持,那么客户端就以TSL/SSL的方式发送数据,否则以原来的方式发送数据

TSL、SSL、STARTTLS区别和关系:TSL/SSL提供一种方式网络间的一个加密通信通道,STARTTLS可选择使用TSL/SSL

想了解更多详情可点击进入 Xmpp官网

服务器端选择

客户端选择

即可选择现成的开源实现,也可基于实现了XML的开源框架来定制开发.下面是几个例子.

  • spark
  • jwchat
  • conversejs
  • Strophe.js
  • iJab

后续会对每个部分进行详细说明.

参考资料

Xmpp官网
环信支持千万并发即使通讯的技术要点

原文地址:https://www.cnblogs.com/lifepai/p/4389899.html