zoukankan      html  css  js  c++  java
  • 储物柜soket通信协议和中间件实现技术细节

    一、中间件程序的职责:

    1)对柜机提供soket长连接的服务器端,就是soket server。可提供上万的客户端同时连接。用来实时响应控制请求,中间件必须随时知道某个柜机的在线状态,外部请求时才能判断是否能够转发消息。

          中间件监听的端口是5880,socket连接的协议是tcp/ip。目前没有加密,明文传输。

        流程说明:

       签到

         柜机socket client发起连接请求,中间件socket接受连接之后, 

         柜机socket client先对中间件socket server发送消息(格式:“ bufferbox_sign_in”+“:”+设备号,如   bufferbox_sign_in:KDL36000001)

         中间件程序把柜机KDL36000001显示为在线状态。

    长连接中断后重连

    柜机socket client和中间件socket server建立连接后是有定时发送心跳包的,

    柜机socket client每过30秒检查和中间件socket serverd的连接状态,发起0字节的发包请求,如果发生异常则实际连接情况发生变化,

    柜机socket client断开连接,重新尝试建立连接重新发起签到。

    2)对外部暴露RESTful风格的api,供外部各种应用和程序调用,响应外部的http get/post请求。

    api原型,.net webapi:

     [HttpGet]
            /// <summary>
            /// 储物柜取物开箱接口(取件)
            /// </summary>
            /// <param name="StationNo">设备唯一编号  设备不存在或者设备编号有误!</param>
            /// <param name="CellNo">箱格编号</param>
            /// <returns></returns>
            public ApiActionResult BufferBox_Collect(string StationNo, string CellNo)
            {
                var result = new ApiActionResult()
                {
                    Success = false,
                    Result = null,
                    Message = "操作失败。"
                };
                string msg = string.Empty;
                using (var db = new BufferBoxDBEntities())
                {
                    var stationEntity = db.station_signin_session.Where(st => st.SessionDict == StationNo).FirstOrDefault();
                    if (stationEntity == null)
                    {
                        result.Message = "设备不存在或者设备编号有误!";
                        result.Result = "";
                        return result;
                    }
                    #region API_Request_session
                    var requestEntity = new API_Request_session
                    {
                        API_Request_IP = Request.GetClientIpAddress(),
                        RequestID = Guid.NewGuid(),
                        RequestData = CellNo + "|Collect",
                        RequestDataTime = DateTime.Now,
                        ResultData = JsonConvert.SerializeObject(new CommandResultDTO { CellNo = CellNo, Action = "取件", ResultMessage = "中间件已转发,设备还未回复。" }),
                        ExecuteFlag = false,
                        StationNo = StationNo
                    };
                    db.API_Request_session.AddObject(requestEntity);
                    #endregion
                    db.SaveChanges();
                    //Com.DataCool.DotNetExpand.LogHelper.Info(JsonConvert.SerializeObject(requestEntity));
                    msg = "api_request:" + JsonConvert.SerializeObject(requestEntity);
                    result.Success = true;
                    result.Message = "设备已经受理请求。";
                    result.Result = requestEntity.RequestID.ToString();
                }
                if (!string.IsNullOrEmpty(msg))
                {
                    Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    try
                    {
                        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(conf.AppSettings.Settings["Middleware_IP"].Value), Convert.ToInt32(conf.AppSettings.Settings["Middleware_PORT"].Value)));
                        clientSocket.Send(Encoding.UTF8.GetBytes(msg));
                    }
                    catch { }
                }            
                return result;
            }

    流程说明:

    webapi响应外部的http get请求后,根据api的参数StationNo,CellNo获取到本次请求的设备和对应箱格。然后向中间件socket server发起一个socket client连接,建立连接后发送消息“api_request”+“:”+请求内容(后面附格式),中间件在内存上下文找到柜机socket client连接对象转发刚才的webapi发出的消息。柜机socket client收到中间件socket server的api_request消息 马上执行对控制板发送开锁指令。然后立即回复中间件socket server消息格式是“command_result”+“:”+处理过的请求内容(后面附格式) 中间件socket server收到消息将本次请求的结果修改为执行成功,这样完成了一次完整的操作

    附请求内容json格式:

    api_request:{"$id":"1","RequestID":"066a395a-486f-4e93-b782-fbf889e1d52f","Token":null,"RequestData":"11|Deposit","ResultData":"{"CellNo":"","ResultMessage":"中间件已转发,设备还未回复。","Action":"存件"}","RequestDataTime":"2016-07-16T12:00:53.9329622+08:00","ResultDataTime":null,"ExecuteFlag":false,"API_Request_IP":"183.70.83.165","StationNo":"SHYH24000001","EntityKey":{"$id":"2","EntitySetName":"API_Request_session","EntityContainerName":"BufferBoxDBEntities","EntityKeyValues":[{"Key":"RequestID","Type":"System.Guid","Value":"066a395a-486f-4e93-b782-fbf889e1d52f"}]}}

    RequestID是每次外部请求的guid,代表每次请求的唯一请求编号,

    RequestData是请求的实际内容

    ResultData是另一个api要回复外部请求的内容

    RequestDataTime是发起请求的时间

    ResultDataTime是柜机客户端回应的时间

  • 相关阅读:
    定时任务的分布式调度
    springmvc 静态资源 配置
    activemq 持久化
    函数式编程与面向对象编程的比较
    LeetCode 108——将有序数组转化为二叉搜索树
    LeetCode 104——二叉树中的最大深度
    LeetCode 700——二叉搜索树中的搜索
    线性代数之——四个基本子空间
    线性代数之——线性相关性、基和维数
    线性代数之——秩和解的结构
  • 原文地址:https://www.cnblogs.com/datacool/p/datacool2016_bufferbox_middleware.html
Copyright © 2011-2022 走看看