一.朋友圈的基本单元——动态

首先定义一个自定义控件用来显示每条动态。

二.运行效果

      

三.核心解读

PushedMessage 有个PushIndex属性,表示发送消息的index,从0开始递增。每个人Push的index都是从0开始,ResponseMoments 的 MessageList 是个字典,Key表示 index。

        //
// 摘要:
// 拉取我的朋友们发的消息。当收到服务器回复,将触发ResponseMomentsReceived事件。
//
// 参数:
// startPullIndex:
// 从哪个index的消息开始拉取(不包含该index对应的那条)。如果startPullIndex小于0,表示拉取最新的N条。
//
// latest:
// latest为true,表示拉取更新的(大于startPullIndex);为false表示拉取之前的(小于startPullIndex)。
void Pull(long startPullIndex, bool latest);
//
// 摘要:
// 拉取目标用户所发的消息。当收到服务器回复,将触发ResponseMomentsReceived事件。
//
// 参数:
// ownerID:
// 所要拉取的目标用户的ID
//
// startPushIndex:
// 从哪个index的消息开始拉取(不包含该index对应的那条)。如果startPushIndex小于0,表示拉取最新的N条。
//
// latest:
// latest为true,表示拉取更新的(大于startPullIndex);为false表示拉取之前的(小于startPullIndex)。
void Pull(string ownerID, long startPushIndex, bool latest);

当调用这个方法时,表示获取我的朋友们的动态,我朋友们的动态会排序,index就是用这个key表示的。

latest 参数 表示是下拉,还是上拉。

四.DynamicsLoader解读

DynamicsLoader中最主要的是Load方法。

  public void Load(Dictionary<long, PushedMessage> currentMessageList, FlowLayoutPanel flowLayoutPanel, IMomentsClient client)
{
this.preLastIndex = this.lastIndex;
foreach (var item in currentMessageList)
{
if (this.firstIndex < )
{
this.firstIndex = item.Key - currentMessageList.Count + ;
}
if (item.Key < this.firstIndex)
{
this.firstIndex = item.Key;
}
if (item.Key > this.lastIndex)
{
this.lastIndex = item.Key;
}
if (!this.messageList.ContainsKey(item.Key))
{
this.messageList.Add(item.Key, item.Value);
}
}
this.freeIndex = this.lastIndex - ; if ((this.lastIndex - this.preLastIndex) > )
{
this.firstIndex = this.lastIndex - currentMessageList.Count + ;
this.preLastIndex = this.firstIndex;
this.freeIndex = this.preLastIndex;
this.messageList.Clear();
this.messageList = currentMessageList;
}
this.listIndex = new List<long>((IEnumerable<long>)this.messageList.Keys);
this.listIndex.Sort();
flowLayoutPanel.Controls.Clear();
foreach (var item in this.listIndex)
{
DynamicsControl crl = new DynamicsControl();
crl.Initialize(this.messageList[item].OwnerID, Encoding.UTF8.GetString(this.messageList[item].Content), this.messageList[item].PushTime);
flowLayoutPanel.Controls.Add(crl);
flowLayoutPanel.Controls.SetChildIndex(crl, );
}
this.listIndex.Clear();
this.listIndex = null;
if (this.isUp)
{
if (flowLayoutPanel.Controls.Count != )
{
flowLayoutPanel.ScrollControlIntoView(flowLayoutPanel.Controls[]);
}
}
else
{
if (flowLayoutPanel.Controls.Count != )
{
flowLayoutPanel.ScrollControlIntoView(flowLayoutPanel.Controls[flowLayoutPanel.Controls.Count - ]);
}
}
if (currentMessageList.Count == )
{
return;
}
if ((this.lastIndex - this.preLastIndex) < )
{
return;
}
do
{
client.Pull(this.freeIndex, false);
this.freeIndex -= ;
}
while (this.freeIndex > this.preLastIndex);
}

正如前面所言,每一条动态都有一个index,那么我每次获取动态的时候,就需要保留一个最小的索引,用于下拉的时候使用;保留一个最大的索引,用于上拉的时候使用。当最新的动态比本地的动态多出20条以上时,则分为两种情况:1.两次可以加载完的就加载两次 ,2两次无法加载完的,就只加载最新的20条,并将本地旧动态全部删除。

五.移动端如何通信

一.消息编解码总体策略

NPush默认使用紧凑的序列化器,其遵循的策略如下:
字符串一律使用UTF-8编码。如果是基础数据类型,则直接记录其字节。
如果是bool,则用一个字节表示,0表示false,1表示true。
如果是string,先记录其长度(int,-1表示为null,0表示string.Empty),再记录UTF8编码的字节。
如果是byte[],先记录其长度(int,-1表示为null),再记录其内容。
如果是Image ,先记录其长度(int,-1表示为null),再记录是否为Gif(一个byte),再记录序列化内容。
如果是Color ,长度固定为3个字节,一次记录R/G/B的值。
如果是List<>,先记录元素数(int,-1表示为null),再依次记录每个元素的内容。
如果是Dictionary<,>,先记录元素对的个数(int,-1表示为null),再依次记录每个元素的Key,Value。
如果是自定义的class和struct,则先记录其序列化的长度(int,-1表示为null),再记录其序列化后的内容

二.消息头

消息头固定长度为8。

以登陆请求消息为例:LoginContract,C->S,MessageType为0

三.消息

DeviceType取值: 0 - DotNet ,1 - Android ,2 - iOS

六.序列化原理

在分布式通信系统中,网络传递的是二进制流,而内存中是我们基于对象模型构建的各种各样的对象,当我们需要将一个对象通过网络传递给另一个节点时,首先需要将其序列化为字节流,然后通过网络发送给目标节点,目标节点接收后,再反序列化为对象实例。

为了将业务对象转换为二进制流,大家通常有两种方案可以选择:使用.NET自带的二进制序列化器,或,先将业务对象转换为字符串(比如xml),再将结果用类似UTF8进行编码得到字节流。 然而这两种方案都有缺陷。

1..NET自带的二进制序列化器

缺点:强侵入性,序列化结果臃肿,其size巨大,效率低下,加密困难。

2.通过string进行中转

缺点:需要自己打造协议对象与字符串之间的相互转换、序列化之后的结果的Size取决于我们协议对象与字符串之间相互转换时所采用的规则,同样也取决于我们的耐心程度 、同.NET自带的二进制序列化器,对象属性值的读取/设置、对象的创建等通常也是基于反射的,所以,效率同样存在问题。

基于上述,我选择采用自己的序列化方式,性能较.NET自带的二进制序列化器提高了7~8倍。

七.源码下载

(说明:压缩包中有SQL脚本,我使用的是Mysql数据库。客户端登陆账号为test01~test99,以及默认的testQQ。相应的好友关系可以查看服务端的TestFriendProvider类。 )

     安卓客户端下载

——————————————————————————————————————

推荐阅读 :那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程

实现过程全纪录——自己写一个“微信朋友圈”(包括移动端与PC端)的更多相关文章

  1. Android 高仿微信朋友圈动态, 支持双击手势放大并滑动查看图片。

    转载请注明出处:http://blog.csdn.net/sk719887916/article/details/40348873 作者skay: 最近参与了开发一款旅行APP,其中包含实时聊天和动态 ...

  2. ionic 实现微信朋友圈分享的完整开发流程

    最近开始要着手负责开发ionic的项目了,一直很好奇想实现一个微信朋友圈分享的功能,所以我就网上找了找文章来练手实现,果不其然,找到了几篇,但是发现它们的流程都不太详细,清楚,直接,还有不少坑. 今天 ...

  3. iOS版微信朋友圈数据库的简要分析

    本文版权归cxun所有,如有转载请注明出处与本文链接,谢谢!原文地址:http://www.cnblogs.com/cxun/p/4550523.html 之前写了一些关于微信聊天记录的博文之后,不少 ...

  4. 微信朋友圈如何同时分享(图片+文字) Android版

    以下是:微信朋友圈SDK 分享图片的代码,但只能分享图片,不能分享文字,如何才能图片和文字同时分享?求各位大神指教! public class MainActivity extends Activit ...

  5. 如何利用Python网络爬虫抓取微信朋友圈的动态(上)

    今天小编给大家分享一下如何利用Python网络爬虫抓取微信朋友圈的动态信息,实际上如果单独的去爬取朋友圈的话,难度会非常大,因为微信没有提供向网易云音乐这样的API接口,所以很容易找不到门.不过不要慌 ...

  6. 实训六(Cocos2dx游戏分享到微信朋友圈----AppID的获取)

    考虑把游戏分享到微信朋友圈,前面的博文已经写到,shareSDK是一个很好的选择,但是学习了几天时间,遇到了很多问题,与其在一棵树上吊死,还不如退一步海阔天空,先暂时放一放,于是我考虑了一下既然是分享 ...

  7. Android 仿微信朋友圈发动态功能(相册图片多选)

    代码分享 代码名称: 仿微信朋友圈发动态功能(相册图片多选) 代码描述: 仿微信朋友圈发动态功能(相册图片多选) 代码托管地址: http://www.apkbus.com/android-15276 ...

  8. python爬虫24 | 搞事情了,用 Appium 爬取你的微信朋友圈。

    昨天小帅b看到一些事情不顺眼 有人偷换概念 忍不住就写了一篇反讽 996 的 看不下去了,我支持996,年轻人就该996! 没想到有些人看不懂 这就算了 还来骂我 早些时候关注我的小伙伴应该知道我第一 ...

  9. (转载) listview实现微信朋友圈嵌套

    listview实现微信朋友圈嵌套 标签: androidlistview 2016-01-06 00:05 572人阅读 评论(0) 收藏 举报  分类: android(8)  版权声明:本文为博 ...

随机推荐

  1. wget获取https资源

    使用wget获取 https资源,缺省命令下是要使用证书,如果还未安装证书,可以选择忽略. 例如没有github.com的证书,执行如下命令 mkdir -p model cd model wget ...

  2. (中等) CF 555E Case of Computer Network,双连通+树。

    Andrewid the Android is a galaxy-known detective. Now he is preparing a defense against a possible a ...

  3. Windows Azure Storage Client Library 2.0 入门

    入门连接如下: http://gauravmantri.com/2012/11/17/storage-client-library-2-0-migrating-table-storage-code/

  4. Quick Cocos2dx 初步战斗

    呵呵,图片先来一发: 最近懒,很懒,连我自己都觉得有点可耻了. 但是实在没有什么东西啊,温水煮青蛙的什么的. 吐槽完成,以上. 目前完成了简单的战斗部分,AI还需要抽出来. 然后突然之间想到手游的帧频 ...

  5. ArcEngine部分工作总结

    Arcengine工作总结地物点查询本部分可以在一个窗体中实现,也可以在两个窗体中实现.由于工作要求本人是在两个窗体中实现的:弹出窗体的名称为FormQuery主窗体单机查询时间的代码FormQuer ...

  6. redis sentinel 集群监控 配置

    环境: ip  172.16.1.31 26379  redis sentinel ip  172.16.1.30 6379   主 1 ip  172.16.1.31 6380   从 1 ip   ...

  7. scp命令和sftp命令

    scp帮助命令: man scpscp功能:下载远程文件或者目录到本地,如果想上传或者想下载目录,最好的办法是采用tar压缩一下,是最明智的选择.从远程主机下载东西到本地电脑拷贝文件命令 scp us ...

  8. 控制流之if

    if语句if语句用来检验一个条件, 如果 条件为真,我们运行一块语句(称为 if-块 ), 否则 我们处理另外一块语句(称为 else-块 ). else 从句是可选的. ~~~~~~~~~~~~~~ ...

  9. jpg转bmp(使用libjpeg)

    源: jpg转bmp(使用libjpeg) [转]JPEG压缩原理 bmp转jpg(使用libjpeg)

  10. Octave使用感想

    Octave是一门比较 简单.原始 的语言.从某方面来说和 shell 语言类似,只不过,shell语言主要用于 操作系统管理方面,而Octave侧重于科学计算方面. 语言本身没有提供或者说很简单的 ...