该IM就不介绍了。其使用的协议很值得学习,号称无法攻破的通信协议,由于客户端开源而写协议开放,十分方便大家学习。
而wubenqi在github上开源了他编写的开源服务端,最新版本我没有测试,因为给出的源码部分并未涉及protobuf协议定义的源码,但是其基础代码又部分可以拿来学习。
一、tdlib编译与使用
tdlib是官方客户端开发包,使用C++编写
https://github.com/tdlib/td#using-cxx
依赖项包括:
OpenSSL
zlib
gperf (build only)
CMake (3.0.2+, build only)
PHP (optional, for documentation generation)
我在ubuntu20.04编译尚未遇到啥困难,缺少安装啥
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j4
make install
编译历经30分钟,出现如下几个静态库:install可以安装库到系统目录
libmemprof.a
libtdapi.a
libtdclient.a
libtdcore.a
libtdjson_private.a
libtdjson_static.a
二、使用tdlib
编译一下示例程序:
cd ./example/cpp
mkdir build
cd build
cmake ../
make
这里出现了td_example程序,这是一个基础登录并收发消息的示例。
官方说明如下:
https://core.telegram.org/tdlib/getting-started#user-authorization
IM关于消息的存储有2种理念:
1)以会话为中心,1对1私聊与N对N的群组都采用一个模型,参与者都绑定到某个会话ID,然后此会话的消息都可以看做是时序上的数据队列,可以采用读扩散或者使用适当的写扩散减少热点;
2)以用户为中心,每个用户都有发件箱和收件箱,这类似邮件服务的逻辑,这样维护用户的收消息十分方便,在存储上也十分方便,可以提高收件拉取的读效率;但是如果群消息使用这样写扩展逻辑,如果是超级万人大群会变得十分浪费存储资源;
根据前一链接文档,telegram采用如下的存储逻辑:
Private chats: 1对1私聊,每个人都有1份消息拷贝;
Basic groups: 是0-200的小群,每个成员都有一份消息拷贝,后进群的人看不到历史消息;
Supergroups: 200000 人的大群共享一份消息记录,这样新人可以看到群的历史记录. 还有几类特殊的超级大群叫做广播或者频道, 可以有无限的人数,但是只有管理员可写,其他的人员仅仅是可读的,
Secret chats: 密聊使用端到端加密,消息只有设备可见;
每个会话都有一个唯一的标识,一个名字以及可选的图片;库自动帮助维护消息列表,按照最后的接收时间,记录一个position,所以应用只需要监听chat.positions
改变的事件即可,然后根据position.list使用其中的两个字段(position.order, chat.id)来处理所有的聊天消息;
备注,
cpp 设置连接服务器的相关参数如下:
TdExample() {
td::ClientManager::execute(td_api::make_object<td_api::setLogVerbosityLevel>(4));
client_manager_ = std::make_unique<td::ClientManager>();
client_id_ = client_manager_->create_client_id();
//send_query(td_api::make_object<td_api::addProxy>("127.0.0.1", 10808, true, td_api::make_object<td_api::proxyTypeSocks5>()), {});
// add proxy by robin
auto proxy = td_api::make_object<td_api::proxyTypeHttp>("","",false);
auto addProxy = td_api::make_object<td_api::addProxy>("10.128.6.1", 1081, true, std::move(proxy));
// set http proxy
send_query(std::move(addProxy), {});
send_query(td_api::make_object<td_api::getOption>("version"), {});
}
java设置相关连接属性代码如下:
client.send(
new TdApi.AddProxy("15.15.15.15", 12345, true,
new TdApi.ProxyTypeHttp("username","password",false)
),
new ProxyRequestHandler()
);
启动示例程序后,如果能连接成功,则会提示输入手机号,这里需要在前面添加区号
// 如下
+8613800138000
然后在其他的客户端上会收到验证码,这里会提示输入验证码
填写验证码就可以了;