一.应用场景

曾几何时,社交媒体已经驻扎到了几乎每个人的生活中。看看你身边的朋友,有几个不玩朋友圈的?就算他不玩朋友圈,那也得玩微博吧。再没有底线,也得玩QQ空间。

不过,作为程序员的我们,没事还是少上这些社交媒体为妙。反而,我们应该去考虑——如何实现这些社交媒体的开发呢?

我相信一定有不少朋友跟我一样,思考过这个问题,今天我就把自己的成果分享给大家,不一定完美,但求抛砖引玉,请大家多指教!

二.运行效果

下面是我做好的PC端和安卓端的运行界面。让大家先有一个直观的了解。后面我会进一步分享我设计的过程。

1.查看我的“圈子”                         2.查看“testQQ”的主页                  3.发送动态

           

三.开发要点

1.C\S架构——服务端与客户端的核心类——两大引擎

本文所实现的朋友圈功能是基于NPush构建的,其核心组件是用于社交媒体开发的服务端引擎IServerEngine和客户端引擎IMomentsClient 。

(1)服务端引擎IServerEngine:

    //NPush服务端引擎接口。
public interface IServerEngine
{
//NPush服务器配置选项。必须在Initialize方法调用之前设置才有效。
NPushConfiguration Configuration { get; set; }
//日志文件的路径。默认为运行目录下的AppLog.txt文件。
string LogFilePath { get; set; }
//当前连接数。
int UserCount { get; }
//获取在线用户列表。
List<string> GetUsers();
//初始化。
// 参数:
// port:
// 为客户端提供服务的端口
// verifier:
// 用户帐号密码验证器。如果不需要验证,可以传入null。
// friendProvider:
// 好友关系提供者
void Initialize(int port, IUserVerifier verifier, IFriendProvider friendProvider, IMomentsPersister persister);
}

(2)客户端引擎IMomentsClient :

public interface IMomentsClient : IDisposable
{
//与节点服务器之间的TCP连接是否正常?
bool Connected { get; }
// 当前对象是否已经被释放?
bool IsDisposed { get; }
//当与节点服务器之间的TCP连接断开时,触发此事件。(连接断开将会自动重连)
event CbGeneric ConnectionInterrupted;
//当朋友圈有新的动态时,触发该事件。参数:ownerID - infoType - pullIndex
event CbGeneric<string, int, long> NewMomentNotified;
//当朋友圈有我相关的新评论时,触发该事件。参数:remarkUserID - ownerID - pushIndex - remarkType -
//content - tosb
event CbGeneric<string, string, long, int, string, string> NewRemarkNotified;
//当同名的帐号登录当前连接的服务器时,自己将被挤掉线(不再自动重连),触发此事件。
event CbGeneric PushedOut;
//当与服务器重连上并登录完成后,触发此事件。请注意查看事件参数LoginResultType,如果登录失败,则表示当前客户端实例已经失效。
event CbGeneric<LoginResultType> RelogonCompleted;
//当朋友圈消息被删除时,触发此事件。参数:ownerID - pushIndex
event CbGeneric<string, long> RemoveMomentNotified;
//当评论被删除时,触发此事件。参数:ownerID - pushIndex - remarkPassiveID
event CbGeneric<string, long, string> RemoveRemarkNotified;
//当调用Pull方法请求moment列表,得到服务器的回复时,触发此事件。
event CbGeneric<UserMoments> ResponseMomentReceived;
//初始化,并登录到服务器。
// 参数:
// serverIP:
// 服务器的IP
// port:
// 服务器的端口
// userID:
// 登录帐号
// pwd:
// 登录密码
// 返回结果:
// 登录结果
LoginResultType Initialize(string serverIP, int port, string userID, string pwd);
//拉取我的朋友们发的消息。当收到服务器回复,将触发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); // 在朋友圈发送消息。
// 参数:
// msgType:
// 消息类型。
// content:
// 消息内容
// tag:
// 附加tag
// 返回结果:
// 返回PassiveID
string Push(int msgType, byte[] content, string tag);
//朋友圈某条消息评论、点赞、回复评论。
// 参数:
// ownerID:
// 目标消息的发送者ID
// momentPushIndex:
// 目标消息的PushIndex
// remarkType:
// 评论的类型。自定义。比如0表示赞,1表示评论,2表示回复。
// content:
// 评论或回复的内容
// tosb:
// 如果是评论回复,则@用户的帐号
// 返回结果:
// 返回PassiveID
string Remark(string ownerID, long momentPushIndex, int remarkType, string content, string tosb);
//删除自己发的某条消息。
// 参数:
// momentPushIndex:
// 目标消息的PushIndex
void RemoveMoment(long momentPushIndex);
//删除自己发的某条消息。
// 参数:
// momentPassiveID:
// 目标消息的PassiveID
void RemoveMoment(string momentPassiveID);// 删除自己发的某条评论。
// 参数:
// ownerID:
// 目标消息的发送者ID
// momentPushIndex:
// 目标消息的PushIndex
// remarkPassiveID:
// 目标评论的PassiveID
void RemoveRemark(string ownerID, long momentPushIndex, string remarkPassiveID);
}

以上是两个类的定义,更具体的相关说明我将在下文中为大家逐一介绍。

2.基本动作——推(push)与拉(pull)

无论朋友圈、微博还是QQ空间,都有两个基本动作——推(push)与拉(pull)。推出消息,也就是发动态;拉取消息也就是刷动态。当然,更进一步来说,所谓的社交媒体系统,本质上还是一个通信系统。“发送”与“接收”是任何通信中亘古不变的主题。

所以,首先得设计好这两个基本动作。

(1)推(push)——API说明

        // 在朋友圈发送消息。
// 参数:
// msgType:
// 消息类型。
// content:
// 消息内容
// tag:
// 附加tag
// 返回结果:
// 返回PassiveID
string Push(int msgType, byte[] content, string tag);

push方法比较简单,msgType这个参数用在服务端对消息做一些自定义处理的时候。目前的例子中服务端对消息是自动转发的,不涉及到自定义处理。

(2)拉(pull)——API说明

        // 拉取我的朋友们发的消息。当收到服务器回复,将触发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);

pull方法的两个重载,前者是用于拉取“圈子”的动态,后者是用于拉取某位“个人”的动态,这两种模式我将在接下来的“3.“圈子”VS“个人”——两种模式”中进行介绍。

至于startPushIndex,则涉及到我对于“动态”的设计——每条动态都有一个全局唯一的Index。而Pull方法每次都是默认拉取20条冬天,因此,在拉取动态的时候,我们就可以指定起始的Index,也就是startPushIndex,从而获取指定的20条动态。关于这个Index,在接下来的3中,我们可以进一步了解。

而latest参数则是表示上拉还是下拉——上拉就是向上刷新,刷取新动态;下拉也就是刷取旧动态。经常玩朋友圈的朋友对这两个操作一定不会陌生。

(3)消息接收的地方——ResponseMomentReceived事件

// 当调用Pull方法请求moment列表,得到服务器的回复时,触发此事件。
event CbGeneric<UserMoments> ResponseMomentReceived;

正如注释所指出的,每次拉取的动态都将由这个事件来返回。我们进一步来看看事件参数UserMoments的定义:

  public class UserMoments
{
public UserMoments();
//是否是请求目标用户所发的朋友圈列表。
public bool IsOwnerList { get; set; }
public Dictionary<long, PushedMessage> MessageList { get; set; }
//如果是请求自己的朋友圈动态,则为自己的ID。如果是请求某个好友Push的消息列表,则为好友的ID。
public string UserID { get; set; }
}

其中MessageList 就是动态信息的集合,这个字典的key就是我们之前说到的Index,字典的Value:PushedMessage,这个我们将在“4.数据库实体”中进一步说明。

3.“圈子”VS“个人”——两种模式

我们知道,朋友圈中既可以查看圈子中的动态,也可以查看某个人的动态。所谓圈子,在朋友圈和QQ空间中就是好友关系,在微博中就是关注关系——实质上并没有区别,所以我们就用好友来概括。

这个好友关系定义在服务端。来看我的简单实现:

   public class TestFriendProvider : IFriendProvider
{
private List<string> list = new List<string>(); public TestFriendProvider()
{
for (int i = ; i < ; i++)
{
list.Add("test" + i.ToString(""));
}
list.Add("testQQ");
} public List<string> GetFriends(string userID)
{
if (string.Equals(userID, "testQQ"))
{
List<string> l = new List<string>();
l.Add("test01");
l.Add("test02");
l.Add("test03");
return l;
}
return this.list;
}
}

这个类的实例将注入到服务端引擎中

this.serverEngine.Initialize(int.Parse(ConfigurationManager.AppSettings["Port"]), new MyUserVerifier(), new TestFriendProvider(), this.persister);

服务端引擎届时将会回调GetFriends方法,从而将某用户发送的动态推送给他的好友。我在例子中采用的是简单的实现,大家要实现自己的朋友关系,只需要自定义IFriendProvider接口的实现即可。

顺便介绍下服务端的另一个注入的接口,IUserVerifier,用于注入用户登录验证的逻辑。下面看下例子中的简单实现:

   class MyUserVerifier:IUserVerifier
{
private List<string> list = new List<string>(); public MyUserVerifier()
{
for (int i = ; i < ; i++)
{
list.Add("test" + i.ToString(""));
}
list.Add("testQQ");
}
public bool VerifyUser(string userID, string password)
{
return this.list.Contains(userID);
}
}

至于某个人的动态则根据对方的ID进行获取即可。

4.数据库实体

(1)PushedMessage

    [Serializable]
public class PushedMessage : IEntity<long>
{
public const string _IsValid = "IsValid";
public const string _OwnerID = "OwnerID";
public const string _PassiveID = "PassiveID";
public const string _PushIndex = "PushIndex";
public const string TableName = "PushedMessage"; public PushedMessage();
public PushedMessage(string owner, long index, PushMomentsContract contract);
// 持久化数据库中的自增ID。
public long AutoID { get; set; }
public byte[] Content { get; set; }
public int InfoType { get; set; }
// 是否有效。如果消息被发送者删除,则变成无效。
public bool IsValid { get; set; }
public string OwnerID { get; set; }
// 由客户端生成的ID。(UserID_时间序列号)
public string PassiveID { get; set; }
public long PushIndex { get; set; }
public DateTime PushTime { get; set;
// 评论列表。
[NotDBField]
public List<Remark> RemarkList { get; set; }
public string Tag { get; set; } public long GetPKeyValue();
public override string ToString();
}

对应的数据库表结构:

(2)PulledMessage

   [Serializable]
public class PulledMessage : IEntity<long>
{
public const string _GuestID = "GuestID";
public const string _PullIndex = "PullIndex";
public const string TableName = "PulledMessage"; public PulledMessage();
public PulledMessage(string guest, PushedMessage msg, long index); public long AutoID { get; set; }
public string GuestID { get; set; }
public string OwnerID { get; set; }
public long PullIndex { get; set; }
[NotDBField]
public PushedMessage PushedMessage { get; set; }
public long PushIndex { get; set; } public long GetPKeyValue();
public override string ToString();
}

对应的数据库表结构:

(3)momentremark

   [Serializable]
public class MomentRemark : IEntity<long>
{
public const string _AutoID = "AutoID";
public const string _IsValid = "IsValid";
public const string _OwnerID = "OwnerID";
public const string _PassiveID = "PassiveID";
public const string _PushIndex = "PushIndex";
public const string TableName = "MomentRemark"; public MomentRemark();
public MomentRemark(string remarkUser, RemarkContract contract); public long AutoID { get; set; } // 评论的内容。
public string Content { get; set; }
// 是否有效。如果消息被发送者删除,则变成无效。
public bool IsValid { get; set; } // 目标Moment的Owner的ID。
public string OwnerID { get; set; }
// 由客户端生成的ID。(UserID_时间序列号)
public string PassiveID { get; set; }
// 目标Moment的PushIndex。
public long PushIndex { get; set; } // 评论的时间。
public DateTime RemarkTime { get; set; }
// 评论的类型。
public int RemarkType { get; set; } // 评论者的ID。
public string RemarkUserID { get; set; } // 消息标记,10个字符(月日时分秒)。由客户端赋值。
public string Token { get; set; } // 如果是评论回复,则@用户的帐号
public string Tosb { get; set; } public long GetPKeyValue();
public Remark ToRemark();
public override string ToString();
}

对应的数据库表结构:

至于如何与数据库交互,这个我已经封装好了

 this.persister 
= new DBMomentsPersister(new MysqlDataConfiguration(ConfigurationManager.AppSettings["DBIP"], int.Parse(ConfigurationManager.AppSettings["DBPort"]), ConfigurationManager.AppSettings["UID"], ConfigurationManager.AppSettings["Pwd"], ConfigurationManager.AppSettings["DBName"]));
this.serverEngine.Initialize(int.Parse(ConfigurationManager.AppSettings["Port"]), new MyUserVerifier(), new TestFriendProvider(), this.persister);

只用构造好注入到服务端引擎即可。

四.部署说明

源码下载 

    安卓客户端下载

说明:

1.压缩包中有SQL脚本,我使用的是Mysql数据库。

2.服务端客户端均有配置文件

3.客户端登陆账号为test01~test10,以及默认的testQQ。

社交媒体(朋友圈、微博、QQ空间)开发一网打尽,PC端移动端都有!——源码来袭!的更多相关文章

  1. Android NineGridLayout — 仿微信朋友圈和QQ空间的九宫格图片展示自定义控件

    NineGridLayout 一个仿微信朋友圈和QQ空间的九宫格图片展示自定义控件. GitHub:https://github.com/HMY314/NineGridLayout 一.介绍 1.当只 ...

  2. 微信移动客户端内部浏览器分享到朋友圈,QQ空间代码

    http://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html <script src="http://re ...

  3. VS2010 .net4.0 登录QQ 获取QQ空间日志 右键选中直接打开日志 免积分 源码下载

    代码有一部分是原来写的  最近翻代码 看到了  就改了一下 CSDN上传源码 上传了几次都没 成功 郁闷   不知道怎么回事 上传不了 想要的留 邮箱 或加群77877965 下载地址在下面 演示地址 ...

  4. Android 调用系统分享文字、图片、文件,可直达微信、朋友圈、QQ、QQ空间、微博

    原文:Android 调用系统分享文字.图片.文件,可直达微信.朋友圈.QQ.QQ空间.微博 兼容SDK 18以上的系统,直接调用系统分享功能,分享文本.图片.文件到第三方APP,如:微信.QQ.微博 ...

  5. 《社交红利》读书总结--如何从微信微博QQ空间等社交网络带走海量用户、流量与收入

    <社交红利--如何从微信微博QQ空间等社交网络带走海量用户.流量与收入>--徐志斌 著 <社交红利>这本书2013年9月才上市,卖的非常火. 我最初是在公司内部的期刊上,看到有 ...

  6. C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  7. c++实现游戏开发中常用的对象池(含源码)

    c++实现游戏开发中常用的对象池(含源码) little_stupid_child2017-01-06上传   对象池的五要素: 1.对象集合 2.未使用对象索引集合 3.已使用对象索引集合 4.当前 ...

  8. 分享微博,qq空间,微信

    <div class="share_class" ><div class="bdsharebuttonbox">    <a hr ...

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

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

随机推荐

  1. SD卡初始化以及命令详解

    SD卡是嵌入式设备中很常用的一种存储设备,体积小,容量大,通讯简单,电路简单所以受到很多设备厂商的欢迎,主要用来记录设备运行过程中的各种信息,以及程序的各种配置信息,很是方便,有这样几点是需要知道的 ...

  2. matlab取模与取余

    mod函数采用floor,rem函数采用fix函数.那么什么是floor和fix? fix(x):截尾取整.如: >> fix([3.4 , -3.4]) ans = 3 -3 floor ...

  3. UVa 10911 - Forming Quiz Teams

    题目大意:给出2*n个点,将这些点配成n对,使得所有点对中两点的距离之和尽量小. 用一个整数的二进制形式表示一个集合的子集,以每个集合为状态进行状态转移.具体参见<算法竞赛入门经典>9.5 ...

  4. EclipseEE导入项目出现的那些问题

    1.显示.project文件丢失, 解决方法:在eclipse中删除和该项目相同的文件名,重新import即可 2.导入没有.classpath和.project文件的项目 解决方法:目前没遇到 3. ...

  5. 笔记整理——使用openssl编程

    error: openssl 的所有解决方案 (2013/6/22 17:39:00) error: openssl/crypto.h: No such file or directory 解决方案 ...

  6. OSG实现场景漫游(转载)

    OSG实现场景漫游 下面的代码将可以实现场景模型的导入,然后在里面任意行走,于此同时还实现了碰撞检测. 源代码下载地址: /* * File : Travel.cpp * Description : ...

  7. nmon在线安装及使用

    安装 mkdir /usr/local/nmon cd /usr/local/nmon wget http://sourceforge.net/projects/nmon/files/nmon_lin ...

  8. 使用PHPMailer发送带附件并支持HTML内容的邮件

    PHPMailer是一个封装好的PHP邮件发送类,支持发送HTML内容的电子邮件,以及可以添加附件发送,并不像PHP本身mail()函数需要服务器环境支持,您只需要设置邮件服务器以相关信息就能实现邮件 ...

  9. Antx简介(ali_PPT)

    Antx的由来: §最早,我们用Makefile来build系统 •Makefile不适合Java的编译 §后来,我们用Ant来build系统 •开始时很不错 •随着项目增多,出现困难 §利用bean ...

  10. 滚轮事件的防冒泡、阻止默认行为的代码(效果是:只让当前div滚动,连当前文档都不滚动的效果)

    //用firefox变量表示火狐代理var firefox = navigator.userAgent.indexOf('Firefox') != -1;function MouseWheel(e){ ...