实现背景:有两个设备(A跟B两个冰箱,两者都装有app),现在需要在A上面控制B进行开门。A需要调用服务器接口,然后服务器发送消息控制B开门;此处记录下服务器端实现过程。
1,包使用的Fleck,直接去nuget里下载安装即可。
2,【这一步可忽略不是重点】app端定死了只能是http的请求,由于各种原因(不做赘述),我们这边只能加了一个路由来重定向一下。在Global的Application_Start方法中加代码
#region 自定义路由
//扩展自定义路由(app请求的地址格式都是 app/xxx/这种)(项目是aps.net)
var defaults = new System.Web.Routing.RouteValueDictionary { { "Controller", "*" }, { "Action", "*" } };
System.Web.Routing.RouteTable.Routes.MapPageRoute("CongGuiRoute", "app/{Controller}/{Action}", "~/CongGui.aspx", true, defaults);//defaults可为null
//RouteConfig.RegisterRoutes(System.Web.Routing.RouteTable.Routes);//官方aspx路由规则
#endregion
//websocket,这是为了启动socket,对后面有用
HS.Common.FleckHelper fleckHelper = HS.Common.FleckHelper.GetFleckHelper();
fleckHelper.StartUp();
2,创建FleckHelper帮助类(里面一些代码都没用到,用到时候再研究研究),里面的日志LogDBHelper类就不提供了,自己记录下就行了。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using Fleck;
namespace HS.Common
{
public class FleckHelper
{
/*客户端保活关键词*/
private static string FLAG = "KeepAlive";
/*服务器返回的保活关键字*/
private static string RETURN_FLAG = "rKeepAlive";
//socket链接池
private static Dictionary<string, IWebSocketConnection> socketsPool;
//sockets链接地址
private static Dictionary<string, string> socketsAddress;
//websocket服务对象
private WebSocketServer server;
//监控端口
private string pointAddress;
//单例模式锁对象
private static object lockObj = new object();
private static FleckHelper fleckHelper = null;
private FleckHelper()
{
socketsPool = new Dictionary<string,IWebSocketConnection>();
socketsAddress = new Dictionary<string, string>();
pointAddress = ConfigurationManager.AppSettings["FleckWebSocketPoint"];
server = new WebSocketServer(pointAddress);
}
/// <summary>
/// 单例模式
/// </summary>
/// <returns></returns>
public static FleckHelper GetFleckHelper()
{
if (fleckHelper == null)
{
lock (lockObj)
{
if (fleckHelper == null)
{
fleckHelper = new FleckHelper();
}
}
}
return fleckHelper;
}
/// <summary>
/// 初始化
/// </summary>
public void Initialization()
{
socketsPool = new Dictionary<string, IWebSocketConnection>();
socketsAddress = new Dictionary<string, string>();
pointAddress = ConfigurationManager.AppSettings["FleckWebSocketPoint"];
server = new WebSocketServer(pointAddress);
}
/// <summary>
/// 启动
/// </summary>
public void StartUp() {
//出错后进行重启
server.RestartAfterListenError = true;
//开始监听
server.Start(socket =>
{
socket.OnOpen = () => //连接建立事件
{
//获取客户端标识
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
LogDBHelper.WriteOperatDiary("websocket", clientUrl + "建立websocket链接");
};
socket.OnClose = () => //连接关闭事件
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
LogDBHelper.WriteOperatDiary("websocket", socketsAddress[clientUrl] + "断开websocket链接,地址" + clientUrl);
};
socket.OnMessage = message => //接受客户端消息事件
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
//心跳消息
if (FLAG == message)
{
socket.Send(RETURN_FLAG);
}
else
{
lock (socketsPool)
{
socketsPool[message] = socket;
}
lock (socketsAddress)
{
socketsAddress[clientUrl] = message;
}
LogDBHelper.WriteOperatDiary("websocket", message + "收到信息" + message + "地址" + clientUrl);
}
};
});
}
/// <summary>
/// 向客户端发送消息
/// </summary>
/// <param name="clientID">客户端标志</param>
/// <param name="message">信息</param>
public void SendMessage(string clientID, string message)
{
lock (socketsPool)
{
IWebSocketConnection socket = null;
socketsPool.TryGetValue(clientID, out socket);
if (socket == null)
{
LogDBHelper.WriteErrorDiarylog("websocket", "websocket链接不存在!"+ clientID);
throw new Exception("websocket链接不存在!");
}
else
{
socketsPool[clientID].Send(message);
LogDBHelper.WriteOperatDiary("websocket", clientID + "发送信息" + message);
}
}
}
/// <summary>
/// 检查一个客户端标志是否有对应链接
/// </summary>
/// <param name="clientID">客户端标志</param>
/// <returns></returns>
public bool Exist(string clientID)
{
IWebSocketConnection socket = null;
lock (socketsPool)
{
socketsPool.TryGetValue(clientID, out socket);
if (socket != null)
{
return true;
}
else
{
return false;
}
}
}
/// <summary>
/// 关闭所有链接
/// </summary>
public void Close()
{
foreach (var item in socketsPool.Values)
{
if (item != null)
{
item.Close();
}
}
}
}
}
3,调用代码:CongGui.appx.cs
using HS.Business;
using HS.Business.Cooperation;
using HS.Common;
using HS.Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class app_CongGui : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.ContentType = "application/json";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("gb2312");
string result = "";
//通过Global路由过来的请求
string Controller = Page.RouteData.Values["Controller"] == null ? null : Page.RouteData.Values["Controller"].ToString();
string Action = Page.RouteData.Values["Action"] == null ? null : Page.RouteData.Values["Action"].ToString();
LogDBHelper.WriteServiceDiaryLog("CongGui", "从柜接口调用:" + Controller + "|" + Action);
if (Controller == "icebox" && Action == "openDoor")
{
result = openDoor();
}
Response.Write(result);
Response.End();
}
/// <summary>
/// 主冰箱控制从冰箱开门 (大冰箱)
/// </summary>
/// <returns></returns>
private string openDoor()
{
try
{
string iceBoxId = Context.Request["iceBoxId"].ToString();
LogDBHelper.WriteServiceDiaryLog("openDoor", iceBoxId + "主冰箱控制从冰箱开门");
if (string.IsNullOrEmpty(iceBoxId))
{
LogDBHelper.WriteErrorDiarylog("openDoor", "冰箱信息错误");
return "冰箱信息错误!";
}
using (AP_Equ_IceBoxBB iceBoxBB = new AP_Equ_IceBoxBB())
{
var iceBox = iceBoxBB.GetModel(Convert.ToInt32(iceBoxId));
if (iceBox == null)
{
LogDBHelper.WriteErrorDiarylog("openDoor", "未找到冰箱信息");
return "未找到冰箱信息!";
}
using (DV_CompanyBB companyBB = new DV_CompanyBB())
{
var company = companyBB.GetModelByCompanyId(iceBox.corpId);
if (company == null)
{
LogDBHelper.WriteErrorDiarylog("openDoor", "冰箱关联企业信息错误");
return "冰箱关联企业信息错误!";
}
//websocket发送开门信息
var message = new JObject();
message["hospitalcode"] = company.companyNo;
message["iceboxNo"] = iceBox.iceBoxNo;
message["machineCode"] = iceBox.controlBoardCode;
message["boxNo"] = "";
message["type"] = 5;
message["description"] = "";
message["data"] = null;
FleckHelper fleckHelper = FleckHelper.GetFleckHelper();
fleckHelper.SendMessage(iceBox.controlBoardCode, message.ToString());
//创建开锁记录
using (AP_OP_IceBoxLockListBB iceboxLockBB = new AP_OP_IceBoxLockListBB())
{
AP_OP_IceBoxLockListData iceboxLock = new AP_OP_IceBoxLockListData();
iceboxLock.iceBoxId = iceBox.id;
iceboxLock.freezeAreaId = 0;
iceboxLock.dt = DateTime.Now.ToString();
iceboxLock.lockState = "主冰箱控制从冰箱开门";
iceboxLockBB.AddRecord(iceboxLock);
}
return @"{""Desc"":""获取成功"",""Type"":0,""Code"":""0000""}";
}
}
}
catch (Exception e)
{
return e.Message;
}
}
}
4,写在最后:这是第一次用,所以代码理解上可能偏差地方,欢迎各位指出错误以更好的更正。这里仅仅是做一个记录,方便以后翻阅。还可以看看这篇帖子网页端是如何实现的https://blog.csdn.net/weixin_46867655/article/details/106799674。