.Net 使用SuperSockect实现 TCP服务端与客户端的实时通信(一)

本章主要实现TCP服务端功能的实现,客户端功能实现参见https://blog.csdn.net/liwan09/article/details/106320716

一、项目创建

1、VS2017创建winform项目

2、Nuget搜索安装SuperSocket.Engine

二、服务端功能实现

1、由于supersockect依赖log4net,需要对log4net进行设置,参考https://blog.csdn.net/liwan09/article/details/106266346

2、界面设计

3、 后端代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
using System.Configuration;
using log4net;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Config;
using Bosch.Rtns.Sockect.Model;
using Bosch.Rtns.Sockect.CommonUtils;

namespace Bosch.Rtns.Sockect
{
    public partial class frmMain : Form
    {
        AppServer appServer;
        ILog loggerManager;
        Dictionary<AppSession, string> socketSessionList = new Dictionary<AppSession, string>();//记录链接的客户端数据
        List<FaultSend> faultSends = new List<FaultSend>();//记录接收的故障消息
        private System.Threading.Timer sendMsgTimer;//消息定时发送
        string webapiUrl = ConfigurationManager.AppSettings["WebApiUrl"].ToString();//webapi接口地址
        int timerInterval = Convert.ToInt32(ConfigurationManager.AppSettings["TimeInterval"].ToString());//定时发送消息间隔 单位秒
        int sendMsgTimes = Convert.ToInt32(ConfigurationManager.AppSettings["SendTimes"].ToString());//消息发送的次数
        public frmMain()
        {
            InitializeComponent();
        }
        /// <summary>
        /// load
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmMain_Load(object sender, EventArgs e)
        {
            loggerManager =LogManager.GetLogger("Logger");
            txtIPAddress.Text = "127.0.0.1";
            txtPort.Text = "4141";
            btnEnd.Enabled = false;
        }
        /// <summary>
        ///开启服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            string ipAddress = txtIPAddress.Text.Trim();
            string port = txtPort.Text.Trim();
            if (string.IsNullOrEmpty(ipAddress))
            {
                txtIPAddress.Focus();
                MessageBox.Show("请输入IP地址!");
                return;
            }
            if (string.IsNullOrEmpty(port))
            {
                txtPort.Focus();
                MessageBox.Show("请输入端口号!");
                return;
            }
            ServerConfig serverConfig = new ServerConfig();
            serverConfig.Ip = ipAddress;
            serverConfig.Port = Convert.ToInt32(port);
            serverConfig.TextEncoding = "gbk";
            appServer = new AppServer();
            appServer.NewSessionConnected += Sockect_NewSessionConnected;
            appServer.NewRequestReceived += Sockect_NewMessageReceived;
            appServer.SessionClosed += Sockect_SessionClosed;
            if (!appServer.Setup(serverConfig))
            {
                txtLogInfo.Text += "设置Socket服务侦听地址失败!\r\n";
                loggerManager.Error("设置Socket服务侦听地址失败!\r\n");
                return;
            }
            if (!appServer.Start())
            {
                txtLogInfo.Text += "启动Socket服务侦听失败!\r\n";
                loggerManager.Error("启动Socket服务侦听失败!\r\n");
                return;
            }
            txtLogInfo.Text += "Socket启动服务成功!\r\n";
            loggerManager.Info("Socket启动服务成功!\r\n");
            txtIPAddress.Enabled = false;
            txtPort.Enabled = false;
            btnStart.Enabled = false;
            btnEnd.Enabled = true;
            //开启定时消息推送
            sendMsgTimer = new System.Threading.Timer(obj=>SendMsgTimer(),null, 200,timerInterval*1000);
        }
        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEnd_Click(object sender, EventArgs e)
        {
            if (appServer != null)
            {
                appServer.Stop();
                appServer = null;
                socketSessionList.Clear();
            }
            faultSends.Clear();
            if (sendMsgTimer != null)
            {
                sendMsgTimer.Dispose();
                sendMsgTimer = null;
            }
            txtIPAddress.Enabled = true;
            txtPort.Enabled = true;
            btnStart.Enabled = true;
            btnEnd.Enabled = false;
        }

        /// <summary>
        /// 新的Socket连接事件
        /// </summary>
        /// <param name="session"></param>
        private void Sockect_NewSessionConnected(AppSession session)
        {
            string logMsg = string.Format("{0} 与客户端{1}创建新会话", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), GetwebSocketSessionName(session))+"\r\n";            
            this.Invoke(new Action(() =>
            {
                txtLogInfo.Text += logMsg;
            }));
            loggerManager.Info(logMsg);
            socketSessionList.Add(session, "");
        }
        /// <summary>
        /// 消息接收事件
        /// </summary>
        /// <param name="session"></param>
        /// <param name="value">接收的消息</param>
        private void Sockect_NewMessageReceived(AppSession session,StringRequestInfo stringRequestInfo )
        {
            string receiveMsg = stringRequestInfo.Key;
            string logMsg = string.Format("{0} 从客户端{1}接收新的消息:\r\n{2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), GetwebSocketSessionName(session), receiveMsg) + "\r\n";
            this.Invoke(new Action(() =>
            {
                txtLogInfo.Text += logMsg;
            }));
            loggerManager.Info(logMsg);
            #region 接收数据处理
            if (!string.IsNullOrEmpty(receiveMsg))
            {
                try
                {
                    ReceiveData receiveData = JsonHelper.ConvertToEntity<ReceiveData>(receiveMsg);
                    string msgContent = receiveData.MessageContent;
                    if (receiveData.MessageType == "2")//设备故障推送
                    {
                        EquipmentFault equipmentFault = JsonHelper.ConvertToEntity<EquipmentFault>(msgContent);
                        if (equipmentFault.IsRead == 0)
                        {
                            FaultSend faultSend = new FaultSend();
                            faultSend.EquipmentFault = equipmentFault;
                            faultSend.FaultString = msgContent;
                            faultSends.Add(faultSend);
                            var postResult = CommonUtils.HttpRequest.HttpPost(webapiUrl + "EquipmentFault/Save", msgContent);//调用webapi,数据库保存数据  
                        }
                        else 
                        {
                            //已读的数据
                            var data = faultSends.Where(x=>x.EquipmentFault.Equals(equipmentFault)).FirstOrDefault();
                            if (data != null)
                            {
                                faultSends.Remove(data);
                            }
                        }                                             
                    }
                    else
                    {
                        AppDeviceData appDeviceData = JsonHelper.ConvertToEntity<AppDeviceData>(msgContent);
                        socketSessionList[session] = appDeviceData.DeviceID;
                    }
                }
                catch(Exception ex)
                {
                    string logErrorMsg = string.Format("Error:{0}",ex.Message) + "\r\n";
                    this.Invoke(new Action(() =>
                    {
                        txtLogInfo.Text += logErrorMsg;
                    }));
                    loggerManager.Info(logErrorMsg);
                }
            }           
            #endregion
        }
        /// <summary>
        /// sockect客户端断开连接事件
        /// </summary>
        /// <param name="session"></param>
        /// <param name="value"></param>
        private void Sockect_SessionClosed(AppSession session, SuperSocket.SocketBase.CloseReason value)
        {
            string logMsg = string.Format("{0} 与客户端{1}的会话被关闭 原因:{2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), GetwebSocketSessionName(session), value) + "\r\n";
            this.Invoke(new Action(() =>
            {
                txtLogInfo.Text += logMsg;
            }));
            loggerManager.Info(logMsg);
            //判断socketSessionList中的deviceid是否为空,不为空的话,考虑是否有正在推送的消息,如果有,那么停止消息推送
            string deviceId = "";
            if(socketSessionList.TryGetValue(session, out deviceId))
            {
                socketSessionList.Remove(session);
            }
            //消息推送中,移除当前设备的推送消息
            faultSends = faultSends.Where(x=>!x.EquipmentFault.TargetPhoneID.Equals(deviceId)).ToList();
        }
        /// <summary>
        /// 获取连接的客户端的ip地址
        /// </summary>
        /// <param name="webSocketSession"></param>
        private static string GetwebSocketSessionName(AppSession appSession)
        {
            var remoteClient = appSession.RemoteEndPoint;
            return remoteClient.Address + ":" + remoteClient.Port.ToString();
            //return HttpUtility.UrlDecode(appSession.SessionID);
        }
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="msg"></param>
        private void SendMessage(AppSession session, string msg)
        {
            session.Send(msg);            
            //向所有服务端发送消息
            //foreach (var sendSession in session.AppServer.GetAllSessions())
            //{
            //    sendSession.Send(msg);
            //}
        }
        /// <summary>
        /// 定时发送消息
        /// </summary>
        private void SendMsgTimer()
        {
            this.Invoke(new Action(()=> {
                for(int i = 0; i < faultSends.Count(); i++)
                {
                    var sendTime = faultSends[i].SendTime;
                    if (sendTime<sendMsgTimes)
                    {
                        string targetPhoneID = faultSends[i].EquipmentFault.TargetPhoneID;
                        AppSession targetSession = socketSessionList.Where(x => x.Value.Equals(targetPhoneID) && x.Value != "").Select(x => x.Key).FirstOrDefault();
                        if (targetSession != null)
                        {
                            loggerManager.Info("向设备【" + targetPhoneID + "】推送消息\r\n");
                            SendMessage(targetSession, faultSends[i].FaultString);
                            faultSends[i].SendTime++;
                        }
                    }
                }
                faultSends = faultSends.Where(x => x.SendTime < sendMsgTimes).ToList();//更新消息推送列表
            }));
        }
    }
}

4、其他相关代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bosch.Rtns.Sockect.Model
{
    /// <summary>
    /// App端传输的数据
    /// </summary>
    public class AppDeviceData
    {
        /// <summary>
        /// 登录设备的ID
        /// </summary>
        public string DeviceID { get; set; }
        /// <summary>
        /// 登录的账户名称
        /// </summary>
        public string LoginName { get; set; }
        /// <summary>
        /// 剩余电量
        /// </summary>
        public string BatteryLeft { get; set; }
        /// <summary>
        /// 在线状态 0:不在线 1在线 默认在线
        /// </summary>
        public int IsOnline { get; set; } = 1;
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bosch.Rtns.Sockect.Model
{
    /// <summary>
    /// 设备故障信息
    /// </summary>
    public class EquipmentFault
    {
        /// <summary>
        /// 目标手机设备ID
        /// </summary>
        public string TargetPhoneID { get; set; }
        /// <summary>
        /// 故障发生时间
        /// </summary>
        public DateTime FaultTime { get; set; }
        /// <summary>
        /// 消息id
        /// </summary>
        public string MessageUID { get; set; }
        /// <summary>
        /// 消息标题
        /// </summary>
        public string MessageTitle { get; set; }
        /// <summary>
        /// 发送给App(消息类型)
        /// </summary>
        public string SubAPPName { get; set; }
        /// <summary>
        /// 故障等级 Low,Default,High,Emergent
        /// </summary>
        public string EmergenceLevel { get; set; }
        /// <summary>
        /// 是否已读 0:否 1:是 默认否
        /// </summary>
        public int IsRead { get; set; } = 0;
    }
}

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bosch.Rtns.Sockect.Model
{
    /// <summary>
    /// 故障消息推送
    /// </summary>
    public class FaultSend
    {
        /// <summary>
        /// 故障信息
        /// </summary>
        public EquipmentFault EquipmentFault { get; set; }
        /// <summary>
        /// 故障发送次数
        /// </summary>
        public int SendTime { get; set; }
        /// <summary>
        /// 设备故障信息Json字符串
        /// </summary>
        public string FaultString { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bosch.Rtns.Sockect.Model
{
    /// <summary>
    /// 接收的消息
    /// </summary>
    public class ReceiveData
    {
        /// <summary>
        /// 接收的消息类型 1:App端登录 2:设备故障信息推送
        /// </summary>
        public string MessageType { get; set; }
        /// <summary>
        /// 消息内容
        /// </summary>
        public string MessageContent { get; set; }
    }
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值