项目需要用到推送,于是重新研究了下推送框架,最好能够独立成一个服务,与业务无关的服务,可以给所有的项目通用。找了好久最终决定用SinglR 框架。

  Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架。它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息。

  该项目中 由SingalR 管理底层链接,上次逻辑单独封装。

  ServerHub 代码如下。用来接收 客户端链接。

public class ServerHub : Hub
{
private Logger logger = LogManager.GetCurrentClassLogger();
private static ServerManager severManager = new ServerManager();
public void Hello()
{
Clients.All.hello();
}
public void Test(object o)
{
logger.Info(JsonConvert.SerializeObject(o));
Clients.Client(Context.ConnectionId).RecvMessage(Context.ConnectionId, JsonConvert.SerializeObject(o)); }
/// <summary>
/// 供客户端调用的服务器端代码
/// </summary>
/// <param name="message"></param>
public void SendMessage(object data)
{
string dt = JsonConvert.SerializeObject(data);
logger.Info(dt);
try
{
JObject o = JObject.Parse(dt);
string moduleId = o["ModuleId"].ToString();
string[] groupIds = o["GroupId"].ToString().Split(',');
string connectionName = o["RecvName"].ToString();
string content = o["Data"].ToString();
ServerModels send = severManager.GetModelsByConnectionId(Context.ConnectionId);
string type = o["Type"].ToString();
string projectId = o.Property("ProjectId") == null || o["ProjectId"] == null || string.IsNullOrEmpty(o["ProjectId"].ToString())?send.ProjectId: o["ProjectId"].ToString();
//判断是否需要跨模块进行
foreach (string group in groupIds)
{
List<ServerModels> list = severManager.GetRecvConnections(projectId,moduleId, group, connectionName);
foreach (var item in list)
{
try
{
//封装消息
JObject obj = new JObject();
//发送者的信息
obj["ProjectId"] = projectId;
obj["ModuleId"] = moduleId;
obj["GroupId"] = group;
obj["Type"] = type;
obj["Content"] = content;
obj["ServerId"] = item.ServerId; obj["SendName"] = send.ConnectionName;
obj["SendType"] = send.ConnectionType;
obj["SendOther"] = JObject.FromObject(send.Other);
obj["RecvName"] = item.ConnectionName;
obj["RecvType"] = item.ConnectionType;
obj["RecvOther"] = JObject.FromObject(item.Other);
obj["Time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
if (item.IsCache == "")
{
//添加消息
severManager.AddMessageToModels(obj, item.ServerId);
//发送消息
Clients.Client(item.ConnectionId).RecvMessage(JsonConvert.SerializeObject(severManager.GetMessageFromModels(item.ServerId)));
}
else
{
List<JObject> listObj = new List<JObject>();
listObj.Add(obj);
//发送消息
Clients.Client(item.ConnectionId).RecvMessage(JsonConvert.SerializeObject(listObj));
}
logger.Info(JsonConvert.SerializeObject(obj) +"connid:" + item.ConnectionId);
}
catch (Exception e)
{
//severManager.DelConnection(Context.ConnectionId, "", "");
logger.Error(e.Message);
} }
}
}
catch(Exception e)
{
logger.Error(e.Message);
}
}
public void JoinGroup(object data)
{
string dt = JsonConvert.SerializeObject(data);
logger.Info(dt);
try
{
JObject o = JObject.Parse(dt);
string projectId = o["ProjectId"].ToString();
//发送者的账号
string connectionName = o["SendName"].ToString();
string connectionType = o["SendType"].ToString();
string moduleId = o["ModuleId"].ToString();
string[] groupIds = o["GroupId"].ToString().Split(',');
string isCache = o["Config"]["IsCache"].ToString();
string content = "JoinGroup";// o["Data"].ToString();
string type = MessageType.JOINGROUP;
//是否有其他信息
object other = Utils.UtilsHelper.GetRequestData<object>((JObject)(o["Config"]), "Other", new object());
foreach (string group in groupIds)
{
List<ServerModels> list = severManager.AddConnection(projectId, this.Context.ConnectionId, connectionName, connectionType, moduleId, group, isCache,other);
foreach (var item in list)
{
try
{
JObject obj = new JObject();
obj["ServerId"] = item.ServerId;
obj["SendName"] = connectionName;
obj["SendType"] = connectionType;
obj["SendOther"] = JObject.FromObject(other);
obj["RecvName"] = item.ConnectionName;
obj["RecvType"] = item.ConnectionType;
obj["RecvOther"] = JObject.FromObject(item.Other);
obj["ModuleId"] = moduleId;
obj["GroupId"] = group;
obj["Type"] = type;
obj["Content"] = content;
obj["Time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
//添加消息,去掉
severManager.AddMessageToModels(obj, item.ServerId);
Clients.Client(item.ConnectionId).RecvMessage(JsonConvert.SerializeObject(severManager.GetMessageFromModels(item.ServerId)));
logger.Info(JsonConvert.SerializeObject(obj) + "connid:" + item.ConnectionId);
}
catch (Exception e)
{
//severManager.DelConnection(Context.ConnectionId, "", "");
logger.Error(e.Message);
}
}
}
}
catch(Exception e)
{
logger.Error(e.Message);
} }
public void LeavelGroup(object data)
{
string dt = JsonConvert.SerializeObject(data);
logger.Info(dt);
try
{
JObject o = JObject.Parse(dt); ;
string moduleId = o["ModuleId"].ToString();
string[] groupIds = o["GroupId"].ToString().Split(',');
string content = "LeavelGroup";// o["Data"].ToString();
string type = MessageType.LEVEALGROUP;
ServerModels send = severManager.GetModelsByConnectionId(Context.ConnectionId);
foreach (string group in groupIds)
{
List<ServerModels> list = severManager.DelConnection(Context.ConnectionId, moduleId, group);
foreach (var item in list)
{
try
{
JObject obj = new JObject();
obj["ServerId"] = item.ServerId;
obj["SendName"] = send.ConnectionName;
obj["SendType"] = send.ConnectionType;
obj["SendOther"] = JObject.FromObject(send.Other);
obj["RecvName"] = item.ConnectionName;
obj["RecvType"] = item.ConnectionType;
obj["RecvOther"] = JObject.FromObject(item.Other);
obj["ModuleId"] = moduleId;
obj["GroupId"] = group;
obj["Type"] = type;
obj["Content"] = content;
obj["Time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
Clients.Client(item.ConnectionId).RecvMessage( JsonConvert.SerializeObject(severManager.GetMessageFromModels(item.ServerId)));
logger.Info(JsonConvert.SerializeObject(obj));
}
catch (Exception e)
{
//severManager.DelConnection(Context.ConnectionId, "", "");
logger.Error(e.Message);
}
}
}
}
catch(Exception e)
{
logger.Error(e.Message);
} }
public void ReplyMessage(string data)
{
logger.Info(data);
try
{
if (string.IsNullOrEmpty(data))
{
return;
}
severManager.DelMessageFromModels(data);
}
catch(Exception e)
{
logger.Error(e.Message);
}
}
public void GetAllClients(object data)
{
string dt = JsonConvert.SerializeObject(data);
logger.Info(dt);
try
{
JObject o = JObject.Parse(dt);
string projectId = o["ProjectId"].ToString();
string moduleId = o["ModuleId"].ToString();
string groupId = Utils.UtilsHelper.GetRequestData<string>(o, "GroupId", "");
string type = MessageType.AllCLIENT;
List<ServerModels> list = severManager.GetRecvConnections(projectId, moduleId, groupId);
JArray ay = new JArray();
JObject obj = new JObject();
obj["ModuleId"] = moduleId;
obj["Type"] = type;
JArray array = new JArray();
foreach (var item in list)
{
JObject o1 = new JObject();
o1["ConnectionName"] = item.ConnectionName;
o1["Other"] = JObject.FromObject(item.Other);
array.Add(o1);
}
obj["Content"] = array;
obj["Time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
ay.Add(obj);
Clients.Client(Context.ConnectionId).RecvMessage(JsonConvert.SerializeObject(ay));
logger.Info(JsonConvert.SerializeObject(ay));
}
catch(Exception e)
{
logger.Error(e.Message);
} }
/// <summary>
/// 客户端连接的时候调用
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
logger.Info(Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
logger.Info(Context.ConnectionId);
severManager.DelConnection(Context.ConnectionId, "", "");
return base.OnDisconnected(true);
}
public override Task OnReconnected()
{
logger.Info(Context.ConnectionId);
return base.OnReconnected();
} }

  ServerManager 用来管理 业务逻辑。

public class ServerManager
{
private static Logger logger = LogManager.GetCurrentClassLogger();
public static List<ServerModels> listServer = new List<ServerModels>();
public static List<ProjectModels> listProject = new List<ProjectModels>();
private static bool isInited = false;
public ServerManager()
{
//if(!isInited)
//{
// string [] array = ConfigurationManager.AppSettings["ProjectId"].ToString().Split(',');
// foreach (var item in array)
// {
// ProjectModels project = new ProjectModels();
// project.ProjectId = item;
// listProject.Add(project);
// isInited = true;
// }
//}
}
public ServerModels IsExsitServerModels(string projectId, string connectionName, string connectionType,string moduleId, string groupId)
{
return listServer.FirstOrDefault(x => x.ProjectId == projectId && x.ModuleId == moduleId && x.GroupId == groupId && x.ConnectionName == connectionName && x.ConnectionType == connectionType);
}
public bool IsExsitProjectModels(string projectId)
{
return listProject.FirstOrDefault(x => x.ProjectId == projectId) == null ? false : true;
}
public ServerModels GetModelsByConnectionId(string connectionId)
{
return listServer.FirstOrDefault(x => x.ConnectionId == connectionId);
} /// <summary>
/// 添加链接到数据库
/// </summary>
/// <param name="projectCode"></param>
/// <param name="connectionId"></param>
/// <param name="connectionName"></param>
/// <param name="moduleName"></param>
/// <param name="groupName"></param>
/// <param name="moduleGroupType"></param>
/// <returns></returns>
public List<ServerModels> AddConnection(string projectId,string connectionId,string connectionName, string connectionType,string moduleId,string groupId,string isCache,object other)
{
logger.Info(string.Format("projectCode:{0},connectionId:{1},connectionName:{2},moduleId:{3},groupId:{4}",
projectId, connectionId, connectionName, moduleId, groupId));
List<ServerModels> list = new List<ServerModels>();
try
{
//先查看是否存在这个项目
//if(!IsExsitProjectModels(projectId))
//{
// throw new Exception("没有找到这个项目");
//}
ServerModels models = IsExsitServerModels(projectId, connectionName, connectionType, moduleId, groupId);
ServerModels server = new ServerModels();
server.ServerId = Guid.NewGuid().ToString();
if (models != null)
{
server.listMessage = models.listMessage;
listServer.RemoveAll(x => x.ProjectId == projectId && x.ModuleId == moduleId && x.GroupId == groupId && x.ConnectionName == connectionName && x.ConnectionType == connectionType);
server.ServerId = models.ServerId;
}
server.ModuleId = moduleId;
server.GroupId = groupId;
server.ConnectionName = connectionName;
server.ConnectionId = connectionId;
server.ConnectionType = connectionType;
server.ProjectId = projectId;
server.IsCache = isCache;
server.Other = other;
server.CreateTime = DateTime.Now.ToString();
listServer.Add(server); list = GetRecvConnections(projectId, moduleId, groupId);
}
catch(Exception e)
{
logger.Error(e.Message);
}
logger.Info(list);
return list;
}
public void AddMessageToModels(JObject content,string serverId)
{
ServerModels server = listServer.FirstOrDefault(x => x.ServerId == serverId);
if(server != null)
{
listServer.FirstOrDefault(x => x.ServerId == serverId).listMessage.Add(content); }
} public void ClearMessage(string serverId)
{
listServer.FirstOrDefault(x => x.ServerId == serverId).listMessage.Clear();
} public List<JObject> GetMessageFromModels(string serverId)
{
return listServer.FirstOrDefault(x => x.ServerId == serverId).listMessage;
}
public void DelMessageFromModels(string serverId)
{
listServer.FirstOrDefault(x => x.ServerId == serverId).listMessage.Clear();
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="projectCode"></param>
/// <param name="connectionId"></param>
/// <param name="buissinessName"></param>
/// <param name="groupName"></param>
/// <returns></returns>
public List<ServerModels> GetRecvConnections(string projectId,string moduleId,string groupId,string connectionName = "")
{
logger.Info(string.Format("recvConnectionIds:{0},moduleName:{1},groupName:{2}",
connectionName, moduleId, groupId));
List<ServerModels> list = new List<ServerModels>();
try
{
//string projectId = listServer.FirstOrDefault(x => x.ConnectionId == connectionId).ProjectId;
list = listServer.Where(x => x.ProjectId == projectId).ToList<ServerModels>();
if(!string.IsNullOrEmpty(moduleId))
{
list = list.Where(x => x.ModuleId == moduleId).ToList<ServerModels>();
}
if(!string.IsNullOrEmpty(groupId))
{
list = list.Where(x => x.GroupId == groupId).ToList<ServerModels>();
}
if(!string.IsNullOrEmpty(connectionName))
{
list = list.Where(x => x.ConnectionName == connectionName).ToList<ServerModels>();
} }
catch (Exception e)
{
logger.Error(e.Message);
}
logger.Info(list);
return list;
}
/// <summary>
/// 清楚单个链接
/// </summary>
/// <param name="projectCode"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
public List<ServerModels> DelConnection(string connectionId, string moduleId, string groupId)
{
logger.Info(string.Format("connectionId:{0},moduleName:{1},groupName:{2}",
connectionId, moduleId, groupId));
List<ServerModels> list = new List<ServerModels>();
try
{
string projectId = listServer.FirstOrDefault(x => x.ConnectionId == connectionId).ProjectId;
list = GetRecvConnections(connectionId, projectId,moduleId, groupId); if(!string.IsNullOrEmpty(moduleId))
{
if(!string.IsNullOrEmpty(groupId))
{
listServer.RemoveAll(x => x.ConnectionId == connectionId && x.ModuleId == moduleId && x.GroupId == groupId && x.IsCache != "");
}
else
{
listServer.RemoveAll(x => x.ConnectionId == connectionId && x.ModuleId == moduleId && x.IsCache != "");
}
}
else
{
listServer.RemoveAll(x => x.ConnectionId == connectionId && x.IsCache != "");
}
}
catch(Exception e)
{
logger.Error(e.Message);
}
logger.Info(list);
return list;
} }

  所有的分组都是由上次管理,灵活性 更大一点。

  数据结构设计如下

 public class ServerModels
{
public string ServerId = string.Empty;
public string ModuleId = string.Empty;
public string GroupId = string.Empty;
public string ConnectionId = string.Empty;
public string ConnectionName = string.Empty;
public string ConnectionType = string.Empty;
public string ProjectId = string.Empty;
public string IsCache = "";
public object Other = new object();
public string CreateTime = string.Empty;
public List<JObject> listMessage = new List<JObject>(); }

  该项目提供了这些功能:

  1,不同项目 通过ProjectId 区分,一个Project 对应多个Module .一个 Module 对应多个 Group.一个  Group 对应多个 Connection

  2,  每个链接都能够自由选择是否缓存消息,如果缓存,那么即使离线 ,下次登录 也会收到所有的额消息。

  3,每个链接都可以附带本身的其他消息,给其他用户参考。

  目前推送服务器上线 给主业务提供服务,同事给两个副业务 也同时提供服务。

  其实做完 了之后,发现很多地方都不是很好,稳定性是一个 打的考验。目前缓存数据全部在内存,后期稳定之后 会迁往redis 。发现推送相关的,还有一些优秀的框架,MQTT ,抽空 也试验下。

  这个项目 是集成了android  ios  website  server 。 都使用到了pushserver。 可以互相推送。

  website 代码

define('push', ['jquery', 'common', 'signalr.core', 'signalr.hubs'], function ($, common) {
//var con = $.hubConnection('http://' + requireConfig.pageOptions["RequestAddress"] + '/pushserver/server', { useDefaultPath: false });
var con = $.hubConnection('http://192.168.2.23/pushserver/server', { useDefaultPath: false }); var chat = con.createHubProxy('ServerHub');
var push = {};
push.state = '0'
// 引用自动生成的集线器代理
var dicType = {
"0": "JoinGroup",
"1": "LevealGroup",
"2": "GetAllClients", "11": "AddApplication",//新增申请单
"10": "BackReport",
"13": "DeleteApplication",
"14": "UpdateApplication",
"15": "ReSampled",
"16": "Sampled",
"17": "Diagnosed",//诊断完毕
"18": "UpdateApplication",//修改申请单
"19": "DeleteApplication",//删除申请单
"20": "SampleLock",//采集申请单锁定
"21": "SampleUnLock",//采集申请单解锁定
"22": "CallNumber",//叫号推送
"23": "RequireConfirm",//诊断完毕,请求审核
"24": "ReSample",//重采样推送
"25": "ReDiagnosis",//重新诊断
"26": "ReConfirm",//重新审核
"27": "RequireConsulation",//请求会诊
"28": "ConsulationComplete",//会诊完毕
"29": "RequireDiagnosis",//请求诊断
"30": "Printed",//打印完成
"31": "OverNumber",//过号
"100": "FTS6Diagnosed", //fts6医生诊断完成
"101": "FTS6AddApplication",//FTS6 增加申请单 "200": "Chat", //聊天信息
}
con.stateChanged(function (state) {
conState = state.newState;
if (state.newState != 1) {
if (!window.console) window.console = {};
if (!window.console.log) window.console.log = function () { };
//console.log("comet连接状态改变了" + state.newState);
if (conState == 1) {
window.location.reload()
}
}
});
con.error(function (error) {
console.log('SignalR error: ' + error) });
chat.on('recvmessage', function (message) {
console.log('SignalR recved: ' + message)
// 向页面添加消息
message = JSON.parse(message)
for (var item = message.length - 1; item >= 0; item--) {
if (message[item].ServerId != "") {
chat.invoke('replymessage', message[item].ServerId)
push.Method[message[item].ModuleId](message[item].SendName, message[item].SendType, message[item].GroupId, message[item].ModuleId, dicType[message[item].Type], message[item].Content, message[item].SendOther);
}
}
});
con.start().done(function (error) {
console.log('SignalR connectioned: ' + error)
push.state = '1'
});
push.Method = {};
push.joingroup = function (projectid, moduleid, groupid, sendname, method,iscache,other) {
var data = {
ProjectId: projectid,
ModuleId: moduleid,
GroupId: groupid,
SendName: sendname,
SendType: "",
Config: {
IsCache: iscache,
Other:other
}
}
push.ProjectId = projectid;
push.ModuleId = moduleid;
push.Method[push.ModuleId] = method;
push.GroupId = groupid;
push.SendName = sendname;
push.SendType = "";
chat.invoke('joingroup', data) }
push.sendmessage = function (moduleid, groupid, recvname, type, data, projectId) {
common.WebsiteLog("调用推送函数1");
if (!projectId) {
projectId = "";
}
var dt = {
ProjectId: projectId,
ModuleId: moduleid,
GroupId: groupid,
RecvName: recvname,
Type: type,
Data: data
}
common.WebsiteLog("调用推送函数2");
chat.invoke('sendmessage', dt)
}
push.getallclients = function (projectId,moduleId) {
var dt = {
ProjectId: projectId,
ModuleId: moduleId
}
chat.invoke('getallclients', dt)
}
push.leavelgroup = function (moduleid, groupid) {
var dt = {
ModuleId: moduleid,
GroupId: groupid,
}
chat.invoke('leavelgroup', dt)
}
console.log("complete");
return push;
})

  server 代码

public class PushClient
{ private string url = string.Empty;
private string projectCode = string.Empty;
private HubConnection _conn = null;
private IHubProxy _proxy = null;
public delegate string DelRecvMessage(string m,string content);
public DelRecvMessage recvMessage;
public bool bConn = false;
public PushClient(string url, string projectCode)
{
try
{
this.url = url;
this.projectCode = projectCode;
Init();
}
catch(Exception e)
{
LogClass.WriteLogFile("PushClient:" + e.Message);
} }
private void Init()
{ if (_conn != null)
{
_conn.Dispose();
_conn = null;
}
_conn = new HubConnection(url, true);
_proxy = _conn.CreateHubProxy("ServerHub");
_conn.Error += ex => _conn.Start();
_conn.Closed += () => _conn.Start();
_conn.Start();
_proxy.On<string>("RecvMessage", (obj) =>
{
JArray array = JArray.Parse(obj);
string serverId = array[]["ServerId"].ToString();
_proxy.Invoke("ReplyMessage", serverId);
});
_conn.StateChanged += new Action<StateChange>(tgt =>
{
if (((StateChange)tgt).NewState == Microsoft.AspNet.SignalR.Client.ConnectionState.Connected)
{
Thread.Sleep();
JoinGroup("EcgData", "", "server", "");
bConn = true;
}
else
{
bConn = false;
}
});
}
public void JoinGroup(string moduleId, string groupId, string sendName, string isCache)
{
try
{
JObject o = new JObject();
o["ProjectId"] = projectCode;
o["ModuleId"] = moduleId;
o["SendType"] = "";
o["GroupId"] = groupId;
o["SendName"] = sendName;
JObject config = new JObject();
config["IsCache"] = isCache;
o["Config"] = config;
LogClass.WriteLogFile("JoinGroup:" + JsonConvert.SerializeObject(o));
_proxy.Invoke("JoinGroup", o);
}
catch(Exception e)
{
LogClass.WriteLogFile("JoinGroup:" + e.Message);
} }
public void LeavelGroup(string moduleId, string groupId)
{
try
{
JObject o = new JObject();
o["ModuleId"] = moduleId;
o["GroupId"] = groupId; _proxy.Invoke("LeavelGroup", o);
}
catch(Exception e)
{
LogClass.WriteLogFile("LeavelGroup:" + e.Message);
} }
public void SendMessage(string moduleId, string groupId, string recvName,string type, string data)
{
try
{
JObject o = new JObject();
o["ModuleId"] = moduleId;
o["GroupId"] = groupId;
o["RecvName"] = recvName;
o["Type"] = type;
o["Data"] = data;
LogClass.WriteLogFile("SendMessage:" + o);
_proxy.Invoke("SendMessage", o);
}
catch(Exception e)
{
LogClass.WriteLogFile("SendMessage:" + e.Message);
} }
}

SingalR 构建 推送服务器初探的更多相关文章

  1. 用 centrifugo 搭建 消息推送服务器 docker + rancher 搭建

    关于消息推送服务器 目前有很多第三方的开放成熟的推送服务.鉴于项目需要 我们项目需要自己搭建 自己的推送服务. 我们的推送应用场景 聊天消息 项目内部消息提醒 移动设备接受消息 应用到的相关软件工具知 ...

  2. iOS10 远程推送服务器所需证书以及应用授权文件配置

    推送证书制作步骤(目的:导出服务器需要的p12证书) 第一步: 打开Mac系统的"钥匙串访问"-"证书助理"-"从证书颁发机构请求证书" 取 ...

  3. 【开源】MQTT推送服务器——zer0MqttServer(Java编写)

    目录 说明 功能 如何使用 参考帮助 说明 重要的放前面:V1.0版本是一个非常基础的版本,除了完整的MQTT协议实现外,其他功能什么都没做. MQTT 协议是 IBM 开发的即时通讯协议,相对于 I ...

  4. KindleRSS推送服务器搭建

    参考http://xcode.so/2010/12/google-gae-rss-to-kindle/这篇文章 1.首先尝试在本机搭建服务器直接推送到kindle 需要使用到kindlereader这 ...

  5. WebSocket :Nginx+WebSocket内部路由策略推送服务器的实现(附可生产环境应用代码)

    1.项目背景 前几天写了一篇WebSocket推送的博客:WebSocket :用WebSocket实现推送你必须考虑的几个问题 支持的连接数大概几千个,具体数量依赖于tomcat能并发的线程数,但很 ...

  6. 企业运维实践-丢弃手中的 docker build , 使用Kaniko直接在Kubernetes集群或Containerd环境中快速进行构建推送容器镜像

    关注「WeiyiGeek」公众号 设为「特别关注」每天带你玩转网络安全运维.应用开发.物联网IOT学习! 希望各位看友[关注.点赞.评论.收藏.投币],助力每一个梦想. 本章目录 目录 首发地址: h ...

  7. 微信小程序【消息推送服务器认证C# WebAPI】

    参考微信开发文档: https://developers.weixin.qq.com/miniprogram/dev/api/custommsg/callback_help.html 代码可用 /// ...

  8. cordova 消息推送,告别,消息推送服务器,和 苹果推送证书

    cordova plugin add org.apache.cordova.vibration cordova plugin add https://github.com/katzer/cordova ...

  9. (转)苹果消息推送服务器 php 证书生成

    1.准备好 aps_developer_identity.cer , push.p12这两个证书文件 2. 生成证书如下: openssl x509 -in aps_developer_identit ...

随机推荐

  1. jmeter 后台运行 setsid bin/jmeter -n -t .jmx文件 -l .jtl文件

    备注: 另外,在Linux下我们有时候希望线程可以在后台运行,这样我们关闭当前连接后,线程依然可以运行,这里提供一个将 jmeter命令设置为后台线程的方法. 使用setsid命令:  setsid  ...

  2. php &引用符的注意情况

  3. 数据持久化之嵌入式数据库 SQLite(三)

    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680 SQLite 是 D. Richard Hipp 用 C 语言编写的开源 ...

  4. [轉]User namespaces – available to play!

    User namespaces – available to play! Posted on May 10, 2012by s3hh Over the past few months, Eric Bi ...

  5. Java-技术专区-技术栈分析辨证方法

    1.好多公司动不动就JVM.高并发.分布式.微服务等等,我没有实际经验. 2.从事Java开发三年了,目前的职位是高级Java工程师,感觉技术和工资都到了瓶颈,对以后的发展方向有些迷茫. 3.加班时间 ...

  6. Neo4J(Cypher语句)初识

    欢迎各路大神临幸寒舍 以下节点标签为people,friend,用户自己也可以设置成其他标签,查询时需要用到标签.这个标签可以类比为关系数据库中的表名 创建节点.关系 创建节点(小明):create ...

  7. 【扯淡篇】SDOI2018丶一轮游丶记

    --某不知名蒟蒻的SDOI2018 R1退役场游记&&OI生涯总结 真的是混不下去了. 进队是不可能的, 进队是不可能进队的. 这辈子不可能进队的. 刷题又不会刷 就是靠打表找规律这种 ...

  8. Ubuntu 图形桌面死机重启(机器不重启)

    Ubuntu的图形界面容易死机,如果正在跑程序的话又不能重启.这时候可以通过终端来_重启_图形界面. 首先按Alt+Ctrl+F1进入终端界面.查看图形界面的进程: ps -t tty7 查看到名为X ...

  9. php操作redis--字符串篇

    前提:已经安装好了redis和相关拓展 常用函数:set/get/decr/incr等 应用场景:普遍的key/value存储类型 连接: $redis = new Redis(); $redis-& ...

  10. 同源策略 - JSONP - CORS

    1.  Jquery 对象可以通过 .index() 进行取出自当前元素在父级元素中存放的索引: 2. 浏览器的同源策略 -- Ajax 在访问非本网站的时候,在数据返回的时候,会被浏览器拦截 - 后 ...