问题

QQ 等即时通讯软件的消息传输的技术原理是什么?

回答
QQ 这样的大型即时通讯软件,其消息传输的技术原理是个庞大而复杂的话题,很难用几句话就概括得滴水不漏。但我们可以从几个核心的层面去拆解它,理解其背后是如何运作的。

一、 连接的基石:长连接与心跳机制

想象一下,如果你想随时随地给朋友发消息,电脑或手机就需要时刻准备着接收对方的消息。如果每次发送或接收都像传统网页浏览那样重新建立连接,那效率会低得可怕,而且耗费资源。

所以,QQ这类软件的核心在于建立一种持久的连接,也就是我们常说的长连接。

1. 客户端与服务器端的持续交互: 用户的 QQ 客户端(无论是电脑版还是手机版)会与腾讯的服务器建立一个稳定的 TCP 连接。这个连接一旦建立,并不会因为一段时间没有消息就断开。它就像一条随时待命的电话线。

2. 心跳包: 然而,网络环境瞬息万变,服务器和客户端之间的连接可能会因为各种原因(比如网络波动、路由器重启等)而中断。为了检测连接的健康状况,客户端和服务器之间会定期发送一种叫做心跳包(Heartbeat Packet)的小数据包。

客户端发送心跳: 客户端会按照一个固定的频率(比如每隔几十秒或几分钟)向服务器发送一个非常小的、没有任何实际意义的数据包,仅仅是为了告诉服务器:“我还在线,连接是好的。”
服务器响应与超时: 服务器收到心跳后,会回复一个确认。如果服务器在一定时间内没有收到客户端的心跳(或者客户端在一定时间内没有收到服务器的确认),它就会认为这个连接已经失效,并尝试重新连接。反之亦然。

这个心跳机制保证了在大部分时间里,客户端和服务器之间的连接是激活的,即使没有消息传输,也能及时发现并处理连接中断的问题。

二、 消息的旅程:从发送到接收的路径

当你在 QQ 里发送一条消息时,它并不是直接从你的电脑传到朋友的电脑。整个过程涉及到多个环节和服务器:

1. 客户端打包与加密:
你的输入内容会被客户端捕获,并打包成一个包含发送者信息、接收者信息、消息内容、时间戳等元数据的消息体。
为了安全,这些消息在传输过程中通常会进行加密。QQ 会使用各种加密算法(如 AES、RSA 等)来保证消息内容不被窃听。

2. 发送至接入服务器(Gateway Server):
加密后的消息会通过长连接发送到腾讯的接入服务器(Gateway Server)。接入服务器是用户连接的第一个落脚点,负责处理大量的用户连接请求。

3. 路由与分发(Route Server / Message Server):
接入服务器收到消息后,会交给路由服务器(Route Server)或消息服务器(Message Server)。这些服务器会根据消息的接收者信息,查找接收者的在线状态和连接信息。
在线用户: 如果接收者在线,消息会被直接转发到接收者所在的接入服务器,然后通过长连接直接推送到接收者的客户端。
离线用户: 如果接收者不在线,消息会被暂存在腾讯的消息存储服务器(Message Storage Server)中。当接收者下次上线时,服务器会把离线期间积压的消息一股脑地推送给他的客户端。

4. 消息同步与漫游:
现代即时通讯软件都支持消息漫游,意味着用户可以在不同设备上查看历史消息。这意味着消息在发送后,除了被推送到在线设备,还会被持久化存储在服务器端,并与用户的账号关联。
当用户在另一台设备上登录时,客户端会向消息存储服务器请求下载历史消息,从而实现跨设备的消息同步。

三、 协议的选择与优化

为了高效传输消息,QQ 需要一套专门的通信协议,而不是简单地使用 HTTP。

1. 定制化协议: QQ 很大程度上会使用自定义的二进制协议。相比于文本协议(如 HTTP),二进制协议更紧凑,传输效率更高,解析也更快。这种协议会针对即时消息传输的特点进行设计,比如优化消息头的大小,减少冗余信息。

2. TCP 的可靠性与 UDP 的速度:
TCP (Transmission Control Protocol) 是主流的传输层协议,它提供了可靠的数据传输,包括数据包的顺序保证、错误校验和重传机制。对于消息的发送和接收这种要求高可靠性的场景,TCP 是首选。
然而,TCP 本身也存在一些延迟问题,比如连接建立的“三次握手”以及在丢包时的重传机制。
对于一些对实时性要求极高、但偶尔丢包可以容忍的场景(比如音视频通话),QQ 也可能会结合 UDP (User Datagram Protocol)。UDP 的传输速度更快,但它不保证可靠性。通过在应用层自己实现一些类似 TCP 的可靠性机制(比如序列号、丢包检测和重传),可以达到更好的实时效果。

3. 负载均衡与分布式架构:
QQ 的用户数量庞大,单台服务器根本无法承受。因此,腾讯会构建一个庞大的分布式系统。
负载均衡(Load Balancing): 当用户连接时,会有负载均衡器将请求分配到多台接入服务器中的一台,避免单点过载。
数据分片与分布式存储: 用户数据(包括好友列表、消息记录等)会被分散存储在不同的数据库或存储系统中,保证系统的可扩展性和可用性。

四、 更深层次的考虑

除了上述核心技术,QQ 的消息传输还涉及到许多优化和高级特性:

消息去重: 防止因网络抖动或重传导致的消息重复发送到客户端。
消息排序: 保证接收到的消息顺序与发送顺序一致。
离线推送(Push Notifications): 对于手机端,即使应用不在前台,当收到新消息时,系统会通过 APNS (Apple Push Notification Service) 或 FCM (Firebase Cloud Messaging) 等推送服务唤醒应用并通知用户。这背后也有复杂的 APNS/FCM 服务器交互。
多设备同步: 如何在多台设备上保持消息的实时同步和一致性,需要精巧的状态管理和冲突解决机制。
网络穿透: 解决 NAT 穿透问题,让用户在复杂的网络环境下也能建立连接。例如,使用 UDP Hole Punching 等技术。
安全与隐私: 端到端加密、安全认证等机制,确保消息传输的安全性。

总而言之,QQ 的消息传输并非单一技术,而是集成了长连接、心跳检测、自定义二进制协议、强大的分布式系统架构、消息路由与存储、安全加密等一系列复杂技术的综合体现。它是一个不断迭代和优化的系统,旨在为亿万用户提供稳定、快速、可靠的即时通讯服务。

网友意见

user avatar

题主感兴趣的应该是即时通讯软件的开发.

最简单的即时通讯软件(IM)就是聊天室(Chat Room).

聊天室可以理解为一个包含所有在线用户的QQ群.

服务器会把用户发布的消息广播推送(Push)给所有在线的用户.

这里涉及到即时通讯中的关键操作就是:服务器推(Server Push).

这里以PHP Swoole为例,实现基于现代浏览器WebSocket全双工连接的服务器推:

       浏览器: var ws = new WebSocket("ws://localhost:8080"); ws.onmessage = function(e) {  var msg = JSON.parse(e.data);  console.log(msg.fd);  console.log(msg.data);  console.log(msg.time); }   服务器: $ws = new SwooleWebsocketServer('localhost', 8080); $ws->on('message', function($ws, $frame) {  // 消息格式可以用JSON  $msg = json_encode(array(   'fd' => $frame->fd,   'data' => $frame->data,   'time' => date('Y年m月d日 H:i:s')  ));  // 【服务器推】推送消息给所有客户端  foreach($ws->connections as $fd) { $ws->push($fd, $msg); } });     

上面服务器是向所有连接fd推送消息.

向某个用户对应的连接fd推送,那就是私聊.

向某几个用户对应的连接fd推送,那就是群聊.

道理都类似,关键是建立用户编号uid和连接编号fd的关系.


比如用户1向用户2发送信息"你好":

       浏览器: ws.send(JSON.stringify({"uid": 2, "msg": "你好"})); 服务器: $ws->push($fd, $msg);   服务器推送消息时,需要先判断对方是否在线,是否是其好友. 显然,这些关系判断需要访问数据库如MySQL.     

服务器可以用Redis存储用户2对应的若干个连接(电脑和手机),从而根据用户编号uid找到用户对应的连接编号fd.

比如用户2对应的连接编号为4和6:

       key(uid:2:fd) => value(4, 6)     

Swoole推送消息给用户2时就是这样:

       foreach(array(4, 6) as $fd) { $ws->push($fd, $msg); }     

向群组(多个用户多个连接)推送消息也是同样道理.


用户编号uid和连接编号fd的绑定和唯一约束:

数据库用户表添加一个fd字段(唯一约束),用于记录用户对应的连接编号fd.

唯一约束的fd字段没有内容时,可以使用用户编号的负数作为默认值,做到不违反唯一约束.

用户登录时: onopen 填充fd字段,缓存新的fd到Redis中,旧的fd通过$ws->close($fd)触发onclose事件使其下线.

用户退出时: onclose 清空fd字段,删除缓存Redis中用户对应的该fd.

心跳检测关闭连接时: 也会触发onclose事件.

对于其他异常的连接:

异常关闭的连接的fd如果还在用户表中,下次该fd插入用户表时,因为唯一约束将会导致插入失败.这时需要先删除该fd对应的用户在缓存Redis(或MySQL内存表)中的fd,然后删除该用户在MySQL用户表中的异常fd,最后插入fd到新用户的MySQL记录中.


QQ支持1个账号两个客户端(手机+电脑)同时登录,即允许手机电脑同步在线.

这样用户表fd字段就需要存储2个fd数字,这时就需要自己配合FULLTEXT KEY实现唯一约束.

假设用户1分配得到一个值为100的fd,全文检索用户表的fd字段,查看是否存在包含100的记录:

SELECT * FROM user WHERE MATCH(fd) AGAINST('100' IN BOOLEAN MODE) FOR UPDATE;

假设查询发现用户2的fd字段为'50,100',这时应该删除掉100:

UPDATE user SET fd = '50' WHERE id = 2;

$redis->set('uid:2:fd', '50');

然后往用户1的fd字段加入100(假设用户1本来已经存在一个值为20的fd):

SELECT * FROM user WHERE id = 1 FOR UPDATE;

UPDATE user SET fd = '20,100' WHERE id = 1;

$redis->set('uid:1:fd', '20,100');


心跳检测机制用于回收异常断开的连接.
服务器端WebSocket连接的心跳检测,Swoole已经帮开发者实现,Swoole提供了2个参数:
heartbeat_check_interval: 默认30(心跳检测间隔,单位秒.Swoole会轮询所有TCP连接,将超过heartbeat_idle_time的连接关掉)
heartbeat_idle_time: 默认60(TCP连接的最大闲置时间,单位秒.如果某fd最后一次发包距离现在的时间超过这个值,Swoole会把这个连接关闭)
至于客户端浏览器上的WebSockets心跳检测,则需要开发者自行实现,比如:

       https://github.com/zimv/WebSocketHeartBeat/blob/master/heartBeat.js     


QQ是支持离线消息存储的,也就是如果对方不在线,消息将被持久化到数据库中.
等到对方上线拉取到消息后,数据库里的消息,将会在某个时间后删除.
不过QQ还为用户提供了一个付费的消息漫游服务.
也就是说,消息的存储和处理,仍然离不开传统的数据库CRUD操作.
QQ用户的注册/登录,好友的查找/添加/删除/分组,这些也离不开传统数据库操作.
作为区别,好友上线/下线通知,私聊/群聊(组聊),这些则依赖服务器推.

QQ还支持文件传输,在浏览器里,如果你不用WebRTC提供的点对点P2P的RTCDataChannel技术,可以这样做:用户通过HTTP把文件上传到服务器,然后服务器把文件的URL(字符串)推送给接收文件的用户.
这样做的话,对服务器的带宽和存储压力比较大,传一些小文件(比如图片和文档)还可以,传大文件就太消耗服务器了.

QQ还支持语音和视频聊天,显然,这种场景用点对点的P2P技术最合适,在浏览器里,可以用WebRTC实现.WebRTC里实现点对点的P2P通信,需要一个防火墙打洞服务器ICE(STUN+TURN)来实现NAT穿透:

       https://github.com/coturn/coturn     

WebRTC信令(signaling)的传输可以用WebSocket.
WebRTC已经很大程度简化了P2P实时通信的编程,但对普通Web开发者还是有一定的难度,普通Web开发者还必须熟悉JS会话建立协议JSEP的建立过程,才能跑通WebRTC服务.


最后有一个问题就是,腾讯QQ具有这么大规模的在线用户,不可能所有用户的连接fd都在同一台服务器上,这时就需要实现跨服务器消息推送.也就是Redis里不仅要记录用户对应的fd,而且还要记录这些fd所在的服务器.

比如服务器A上的用户张三向服务器B上的用户李四发送信息. 利用Redis的订阅发布功能,B服务器异步订阅,一旦A服务器发布消息到Redis,B服务器就会即时拿到,然后推送消息给B服务器上的用户李四即可.


还有个问题就是,一些老旧的浏览器比如IE8和IE9都不支持WebSocket协议,这时只能退化到HTTP,比如可以用AJAX长轮询,用PHP+Swoole实现大概可以这样:

       浏览器(接收消息) => AJAX长轮询 => PHP7-Swoole => 异步订阅 => Redis <= 同步发布 <= PHP7-FPM(消息入库) <= 浏览器(发送消息)     

也就是PHP-FPM跟PHP-Swoole通过Redis实现通信.
好处是能利用PHP-Swoole内置的事件驱动异步无阻塞的HTTP服务器和Redis客户端等.

2019/07/01 补充:

用一个字典保存用户(user)和连接(fd)的映射关系,然后根据用户找到对应的连接,从而向该用户推送消息.思路是可行的,但建议引入一个PubSub订阅发布中间件比如Redis,使用订阅发布的模式实现私聊和群聊.
私聊:
用户subscribe订阅自己的用户频道,比如(webim:user:1000:channel).
其他用户给该用户发消息时,向该用户的频道publish发布消息即可.
该用户的订阅事件message会自动触发,在该事件中可以推送消息给用户.
群聊:
用户subscribe订阅自己的群频道,比如(webim:group:2000:channel).
其他用户向该群publish发布消息时,
该用户的订阅事件message会自动触发,在该事件中可以推送群消息给用户.
说明:订阅事件message就是subscribe操作的回调函数.

类似的话题

  • 回答
    QQ 这样的大型即时通讯软件,其消息传输的技术原理是个庞大而复杂的话题,很难用几句话就概括得滴水不漏。但我们可以从几个核心的层面去拆解它,理解其背后是如何运作的。一、 连接的基石:长连接与心跳机制想象一下,如果你想随时随地给朋友发消息,电脑或手机就需要时刻准备着接收对方的消息。如果每次发送或接收都像.............
  • 回答
    这事儿啊,可不小。腾讯质疑抖音涉嫌超范围使用用户 QQ 头像、昵称等信息,并且一纸禁令直接卡了抖音在多闪上的互通,这背后牵扯的可不只是“用头像用名字”这么简单,而是用户数据隐私、平台生态竞争、甚至未来社交格局的微妙博弈。咱们先得把事情捋一捋。腾讯的“指控”:超范围使用用户数据腾讯的逻辑是这样的:很多.............
  • 回答
    QQ音乐这次“一石激起千层浪”的专辑重复购买限制,确实是个不小的信号,预示着音乐平台的内容生态正在经历一场悄无声息的重塑。这件事往大了说,是平台方对音乐消费模式的调整,往小了看,也直接影响到了我们这些乐迷的“钱包”和“体验”。想想看,过去那种“我爱爱豆,我就是要为他贡献销量,哪怕重复买十张我也愿意”.............
  • 回答
    哈哈,这问题简直问到点子上了,我这几年也算是在这些“江湖”里摸爬滚打过来了,跟哥们儿们分享一下我的“江湖秘籍”。知乎:谈笑有鸿儒,往来无白丁(大概是这样吧)在知乎找对象,那感觉就像是在一个高逼格的线上图书馆里寻宝。不是说非得要什么博士硕士,而是你看到一个人在某个领域能侃侃而谈,逻辑清晰,见识不凡,甚.............
  • 回答
    中学生QQ空间里的攀比和早恋,这事儿啊,说起来,咱们都经历过或者听闻过,真是个复杂又普遍的现象。别看这小小的一个网络空间,里面折射出来的,可不仅仅是孩子们爱玩手机那么简单,背后牵扯到成长、家庭、社会,还有那颗颗正在快速变化的心。先说说这“攀比”吧,那真是从进QQ空间的那一刻起,就仿佛上了战场。你想啊.............
  • 回答
    好的,我们来从用户角色和使用场景出发,深入分析主流音乐APP在用户体验上可能存在的问题。这里我们以市面上几个代表性的APP为例(QQ音乐、网易云音乐、酷狗音乐、酷我音乐等,百度音乐和虾米音乐目前已停止服务或合并,故不作为主要分析对象,但其曾经存在的问题也可作为参考)。核心用户角色分析:在分析具体问题.............
  • 回答
    从不更换QQ、微博、人人签名的用户,其性格往往可以从以下几个方面来推测,尽管这只是一个普遍性的观察,并非绝对的定论:1. 稳定与坚持(Stability and Persistence) 核心特征: 这是最直接的联想。签名如同一个人的“社交名片”或“情绪写照”,不更换意味着他们对当前状态的认可,.............
  • 回答
    QQ 群中的表情图片越传越差,这是一个非常普遍的现象,背后涉及到图像压缩、存储、传输以及平台处理等多个环节。下面我将尽量详细地解释其中的原因:核心原因:无损压缩 vs. 有损压缩,以及重复压缩的累积效应首先,我们要明白QQ群里流传的图片,尤其是表情图片,大多数情况下都不是原始的无损格式(如BMP, .............
  • 回答
    你这个问题问得挺实在的,很多人都有这样的顾虑。简单来说,QQ号只要你不主动去注销,理论上是不会被“回收”的。但是,这里的“回收”咱们得掰开了揉碎了说清楚,因为很多时候人们说的“回收”其实包含了几种不同的情况:1. 号码本身不会被“回收”再卖给别人:腾讯官方并没有一个明确的机制叫做“QQ号码回收”,然.............
  • 回答
    在QQ空间里,有时候会看到一些令人不安的图片或者视频,尤其是一些关于食品制作过程的爆料。关于老坛酸菜方便面腌制酸菜的“恶心场面”,这确实在网上引起过很大的关注和讨论。我们来详细梳理一下,这件事是怎么回事,以及它的真实性。事件的起因和流传的内容大概在2022年的时候,有一个关于老坛酸菜包里酸菜制作过程.............
  • 回答
    QQ,这个名字本身就带着一股怀旧的滤镜,每次提起,总能勾起一段段尘封的记忆。要说怀念,太多了,但最让我魂牵梦绕的,大概是它曾经承载的那种纯粹的、无所顾忌的分享和连接。那时候,QQ不仅仅是一个聊天工具,更像是一个私人领域的延伸,一个可以肆无忌惮展示“自我”的空间。还记得那些个性签名吗?每一句都是青春的.............
  • 回答
    QQ,这个名字,在很多人的记忆里,可能伴随着花花绿绿的头像、闪烁的喇叭、还有那些年熬夜聊天的岁月。你说它是“老古董”,没错,它诞生在上个世纪末,是互联网在中国黎明时期的一款标志性产品。但你说它“永远属于这届年轻人”,这话一点不假。为什么明明出了微信这个“后起之秀”,QQ依然能在年轻人群体里稳稳占据一.............
  • 回答
    好的,没问题!想把QQ看点关掉,其实挺简单的,不用太纠结。我这就一步一步给你讲清楚,让你一看就懂。咱们先来说说,为什么你想关掉QQ看点?是不是觉得它占用地方,或者推送的内容不太感兴趣,有时候看着还挺烦人的?反正我身边不少朋友都有这想法。那怎么把它请出去呢?主要有两种方法,一种是直接在QQ里设置,另一.............
  • 回答
    这问题的根源,其实藏在“群”这个字本身所承载的丰富含义里,以及QQ这款产品早期诞生的那个时代背景下。我们一个个来剥开来看。首先,得聊聊“群”字。“群”这个字,在中国文字里,自带一种天然的“聚集”和“共同”的属性。你可以想象一下,一群羊、一群人、一群鸟,它们都是多个个体为了某种目的、某种联系而聚集在一.............
  • 回答
    QQ,这个几乎伴随我们整个互联网成长起来的社交软件,光鲜亮丽的背后,也曾藏着一些让人哭笑不得的小秘密,那些隐藏在界面之下、功能之中的“不为人知”的小插曲。说起来,就像是老朋友偶尔会说漏嘴的陈年往事,添了几分生活气息,也让它显得更真实。我记得有一次,还在用着大概是08、09年左右的版本,那时候的QQ还.............
  • 回答
    QQ号被盗,而且更糟糕的是,密保手机也被改了,绑定了至尊保,这下申诉渠道算是基本被堵死了。客服电话更是打不通,这让人真的是心急如焚。说实话,遇到这种情况,很多人都会觉得绝望,觉得号找不回来了。我身边也有朋友遇到过类似的事情,找回来的过程都异常艰难,而且结局也各不相同。但我还是想尽量详细地帮你梳理一下.............
  • 回答
    在QQ群里,我们经常会遇到这样的尴尬:正聊得热火朝天,话题突然就歪了,或者被别人的新话题强行插入,感觉心塞得很。那么,怎么才能让我们的聊天更顺畅,话题不那么容易被打断呢?这事儿得好好琢磨琢磨。首先,明确群的定位和主要话题 是基础中的基础。一个目标明确的群,大家讨论的方向自然会比较集中。比如,一个游戏.............
  • 回答
    QQ 刚出来的时候,那真是互联网的黄金时代,各种新奇玩意儿层出不穷。要说当时跟进的产品,那真是一抓一大把,基本上只要是有点名气的互联网公司,都想着分一杯即时通讯的羹。但大部分都像流星一样,很快就消失在历史的长河里了。首先得提一下,QQ的出现,确实是抓住了当时互联网发展的一个关键点——信息孤岛的打破。.............
  • 回答
    收到!你想知道QQ聊天时,别人发“这个”是什么意思,并且希望我把解释得详细点,但又不能听起来像AI写的。没问题,这事儿交给我。在QQ聊天里,“这个”这个词本身是挺灵活的,它的意思完全取决于它前面或后面跟着的语境。就好比你吃饭的时候说“这个好吃”,你知道“这个”指的是盘子里的菜;你说“那个那个”,可能.............
  • 回答
    QQ空间大学挂件,这个说实话,想要拿到确实得花点心思,而且不是所有大学都有,也不是随时都能获得。这玩意儿就像是QQ空间里一个独特的“身份徽章”,能证明你是某个大学的学生(或者校友)。首先,得知道是怎么回事儿。QQ空间里的大学挂件,通常是腾讯官方和一些高校合作推出的,或者是针对大学生的某些活动奖励。所.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有