TCP服务监听器,可同时连接接入多个客户端

  • Post author:
  • Post category:其他


监听器宿主是windows服务,

windows服务代码:

public partial class KFService : ServiceBase
    {
        Server Srv = new Server();
        public KFService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
           

            string Msg;
            if (!Srv.Start(out Msg))
            {
                throw new Exception(Msg);
                //this.Stop();
                //this.EventLog.WriteEntry(Msg);
            }
        }

        protected override void OnStop()
        {
            Srv.Stop();
        }

    }

Server.cs

public class Server
    {
        /// <summary>
        /// 主服务线程
        /// </summary>
        private Thread _VSTServiceProccess;
        /// <summary>
        /// TCP服务Socket
        /// </summary>
        private TcpListener _PDAService;
        /// <summary>
        /// 服务超时间隔
        /// </summary>
        private int _ServiceTimeOut;

        /// <summary>
        /// 服务器的IP
        /// </summary>
        private IPAddress _ServerIP;

        /// <summary>
        /// 服务器的服务端口
        /// </summary>
        private int _ServerPoint;
        private byte[] _TransmitKey = null;
        private string _TransmitReaderSn = null;
        //Distinguisher.DistinguisherEquement _DrEquement = null;
        private void WriteLog(string Msg)
        {
            try
            {
                WritLogFile.Log.WriteFile(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff-->") + Msg);
            }
            catch
            { }
        }
        public Server()
        {
            _ServiceTimeOut = 60;
            _ServerIP = IPAddress.Any;

            _ServerPoint = 33555;
            if (!int.TryParse(ConfigurationManager.AppSettings["ServerPort"], out _ServerPoint))
            {
                _ServerPoint = 33555;
                WriteLog("ServerStart:获取主通信端口失败");
            }

        }
       

        /// <summary>
        /// 服务进程启动
        /// </summary>
        public bool Start(out string ErrMsg)
        {
            ErrMsg = null;
            try
            {
                if (_VSTServiceProccess != null)
                {
                    _VSTServiceProccess.Abort();
                    _VSTServiceProccess = null;
                }
                Thread.Sleep(50);


                //本地打开TCP监听
                _PDAService = new TcpListener(_ServerIP, _ServerPoint);
                _PDAService.Start();

                /*循环接收_PDAService监听数据
                 * 创建后台线程m_SendDatas用来发送数据
                 * 最后创建一个新线程ServiceProccess,用来处理已收到的TCP请求,调用m_SendDatas异步发送数据
                */
                _VSTServiceProccess = new Thread(this.PDAServiceProccess);
                _VSTServiceProccess.Start();

                WriteLog("服务启动成功,端口号:" + _ServerPoint.ToString());
                
                return true;
            }
            catch (Exception ex)
            {
                ErrMsg = "服务器启动失败,异常信息 :" + ex.Message;
                WriteLog(ErrMsg);
                
                return false;
            }
        }
        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            if (_VSTServiceProccess != null)
            {
                try
                {
                    _PDAService.Server.Shutdown(SocketShutdown.Both);
                }
                catch { }
                try
                {
                    _PDAService.Stop();
                }
                catch { }
                try
                {
                    _VSTServiceProccess.Abort();
                    _VSTServiceProccess = null;
                }
                catch { }
            }
        }

        /// <summary>
        /// 主服务处理程序
        /// </summary>
        private void PDAServiceProccess()
        {
            while (true)
            {
                try
                {
                    TcpClient Client = _PDAService.AcceptTcpClient();
                    Transmission CS = new Transmission(Client, _ServiceTimeOut, _TransmitKey);
                    Thread ServiceProccess = new Thread(CS.ClientServiceStart);
                    ServiceProccess.Start();
                }
                catch
                {
                    break;
                };
            }
            WriteLog("服务器停止运行!");
        }
        
    }

Transmission.cs

public class Transmission
    {
        private TcpClient _Client;
        private System.Threading.Timer _TimerCheckConn = null;
        private System.Threading.TimerCallback _TimerCallback = null;
        private DateTime _LastDatetime = DateTime.Now;
        private int _Anys = 10000;
        private int _TimeOut = 30;
        private BackgroundWorker m_SendDatas;
        private static object _Sync = new object();
        private byte[] _TransmitKey = new byte[8] { 0xc9, 0xda };
        private byte[] ServerTPDU = { 0x00, 0x00 };
        private byte[] ClientTPDU = { 0x00, 0x00 };

        public static void WriteLog(string Msg)
        {
            try
            {
                WritLogFile.Log.WriteFile(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff-->") + Msg);
                //_LogSW.Flush();
            }
            catch
            { }
        }

        public Transmission(TcpClient Client, int ServiceOut, byte[] TranKey)
        {
            _Client = Client;
            _TimeOut = ServiceOut;
            _Client.NoDelay = true;
            _Client.Client.SendBufferSize = 2048;  接收窗口大小是1360
            _Client.Client.ReceiveBufferSize = 10240;
            

            if (_Client == null)
            {
                WriteLog("不可用的TCP连接Client is null");
                throw new Exception("不可用的TCP连接");
            }
            if (!_Client.Connected)
            {
                WriteLog("不可用的TCP连接Client not Connected");
                throw new Exception("不可用的TCP连接");
            }


            
            if (TranKey != null)
                _TransmitKey = TranKey;

            m_SendDatas = new BackgroundWorker();// 申明后台对象 
            m_SendDatas.WorkerSupportsCancellation = true; // 设置可以取消 
            m_SendDatas.DoWork += new DoWorkEventHandler(SendDatas);

            _TimerCallback = new System.Threading.TimerCallback(this.TimerCheckConn_Tick);
            _TimerCheckConn = new System.Threading.Timer(_TimerCallback, null, _Anys / 2, _Anys);
        }

        private void TimerCheckConn_Tick(object obj)
        {
            if (_LastDatetime.AddMinutes(_TimeOut) < DateTime.Now)
            {
                try
                {
                    if (m_SendDatas.IsBusy)
                        m_SendDatas.CancelAsync();

                    WriteLog(_Client.Client.RemoteEndPoint.ToString() + "连接最后响应时间:" + _LastDatetime.ToString("yyyy/MM/dd HH:mm:ss"));
                    
                    _TimerCheckConn.Dispose();
                    _Client.Client.Shutdown(SocketShutdown.Both);
                    _Client.Client.Close();
                    GC.Collect();
                }
                catch
                { }
            }
        }

        private void SendDatas(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = sender as BackgroundWorker;
            List<byte[]> Datalist = e.Argument as List<byte[]>;
            int l = 6;
            for (int i = 0; i < Datalist.Count; i++)
            {
                if (bw.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }
                //byte[] FeedBackFrameDataSend = Contracts.Encrypt(Contracts.GetSendFrame(Contracts.GetSendCmdData(Datalist[i], Contracts.Equipment)), _TransmitKey);///组装加密
                byte[] FeedBackFrameDataSend = Contracts.GetSendFrame(Contracts.GetSendCmdData(Datalist[i], Contracts.Equipment));//组装
                WriteLog("待发送报文:" + BitConverter.ToString(FeedBackFrameDataSend));
                SocketError Error;
                _Client.Client.Send(FeedBackFrameDataSend, 0, FeedBackFrameDataSend.Length, SocketFlags.None, out Error);

                if (Error == SocketError.Success)
                {
                    WriteLog("发送成功!");
                }
                else
                {
                    i--;
                    
                    if (l < 0)
                        break;
                    l--;

                    WriteLog("发送失败,即将重发,剩余" + l + "次!");
                }
            }
        }

        public void ClientServiceStart()
        {
            if (!_Client.Connected)
            {
                WriteLog("连接中断,即将重启1");
                return;
            }
            NetworkStream NWstm = _Client.GetStream();
            while (true)
            {
                if (!_Client.Connected)
                {
                    WriteLog("连接中断,即将重启2");
                    break;
                }
                try
                {

                    int firstByte = -1;
                    int SecondByte = -1;
                    int thirdByte = -1;
                    int FourByte = -1;
                    bool IsTrue = false;
                    string errorCmd = string.Empty;

                    while ((firstByte = NWstm.ReadByte()) != -1)
                    {
                        if (firstByte == Contracts.ReportHead[0])
                        {
                            SecondByte = NWstm.ReadByte();
                            if (SecondByte != Contracts.ReportHead[1])
                            {
                                errorCmd += Convert.ToString(firstByte, 16) + "-" + Convert.ToString(SecondByte, 16) + "-";
                                break;
                            }
                            thirdByte = NWstm.ReadByte();
                            if (thirdByte != Contracts.ReportHead[2])
                            {
                                errorCmd += Convert.ToString(firstByte, 16) + "-" + Convert.ToString(SecondByte, 16) + "-" + Convert.ToString(thirdByte, 16) + "-";
                                break;
                            }
                            FourByte = NWstm.ReadByte();
                            if (FourByte != Contracts.ReportHead[3])
                            {
                                errorCmd += Convert.ToString(firstByte, 16) + "-" + Convert.ToString(SecondByte, 16) + "-" + Convert.ToString(thirdByte, 16) + "-" + Convert.ToString(FourByte, 16)+"-";
                                break;
                            }
                            IsTrue = true;
                            break;
                        }
                        else
                        {
                            errorCmd += Convert.ToString(firstByte, 16) + "-";
                        }

                    }
                    if (!IsTrue){
                        if (!string.IsNullOrEmpty(errorCmd))
                            WriteLog("无效报文:" + (errorCmd.Length > 0 ? errorCmd.TrimEnd('-') : errorCmd));
                        continue;
                    }
                    WriteLog("***************************************************************************");

                    _LastDatetime = DateTime.Now;
                    报文长度
                    int DgramLength = NWstm.ReadByte() * 256;
                    DgramLength = DgramLength + NWstm.ReadByte();
                    报文数据
                    byte[] FrameDataDecrp = new byte[DgramLength];
                    NWstm.Read(FrameDataDecrp, 0, DgramLength);
                    
                    WriteLog("有效报文:" + BitConverter.ToString(FrameDataDecrp));
                    //拆装解密
                    //byte[] FrameData = Contracts.GetReceiveDataGram(Contracts.Decrypt(Contracts.GetSendFrame(FrameDataDecrp), _TransmitKey));
                    拆装
                    //byte[] FrameData = Contracts.GetReceiveDataGram(Contracts.GetSendFrame(FrameDataDecrp));
                    byte[] FrameData = FrameDataDecrp;
                    
                    CRC验证之前(包含)的错误是致命错误不可修复,忽略处理
                    if (Contracts.CRC16Check(FrameData))
                    {
                        WriteLog("通过CRC校验");
                        设备属性检查
                        if (FrameData[0] == Contracts.Equipment)
                        {

                            
                            while (m_SendDatas.IsBusy) //保证只有一个线程发送数据.避免旧的数据影响新的命令
                            {
                                m_SendDatas.CancelAsync();
                                Thread.Sleep(2);
                            }
                            //将数据传递给数据处理类,返回处理结果
                            List<byte[]> FeedBackFrameList = NetDataProcess.CmdProccess(Contracts.GetSendFrame(FrameData));
                            m_SendDatas.RunWorkerAsync(FeedBackFrameList);  //异步发送不带TPDU数据,避免发送数据时接收不了新命令
                        }
                        else
                        {
                            
                            while (m_SendDatas.IsBusy) //清空服务器回送数据
                            {
                                m_SendDatas.CancelAsync();
                                Thread.Sleep(2);
                            }

                        }
                    }
                    else { WriteLog("未通过校验"); }
                }
                catch (SocketException)
                {
                    
                    try
                    {
                        WriteLog("出现Socket异常,连接已断开");
                        _Client.Client.Shutdown(SocketShutdown.Both);
                        _Client.Client.Close();
                        _Client.Close();
                    }
                    catch { }
                    break;
                }
                catch
                {
                    WriteLog("出现其他异常,连接已断开");
                    continue;
                }
            }
        }
    }

数据处理类

/// <summary>
    /// 处理网络数据,验证接收到的数据是否正确
    /// </summary>
    public static class NetDataProcess
    {
        private static string _reportHead = "A55ACBBC";
        private static byte[] _key = new byte[8] { Convert.ToByte(0xea), Convert.ToByte(0xb8)};


        /// <summary>
        /// PDA业务处理程序
        /// </summary>
        /// <param name="CmdData">命令字和数据</param>
        /// <param name="ClientType">客户端类型:1浏览器本地,2 TCP远程</param>
        public static List<byte[]> CmdProccess(byte[] _DBuf)
        {
            List<byte[]> FeedBackData = new List<byte[]>();
            
            DataProcess dp = null;
            switch ((int)_DBuf[7])
            {
                case (int)NetCmdType.报文错误:   /错误报文不处理
                    WriteLog("报文错误");
                    break;
                case (int)NetCmdType.用户登录请求:
                    dp = new UserLogin();
                    break;
                default:
                    WriteLog("不支持的命令字" + _DBuf[7].ToString("x2"));
                    break;
            }

            if (dp != null)
            {
                dp._rbuf = _DBuf;
                dp.StartProcess("");
                if (dp.Sendbuf == null)
                    WriteLog("发送数据报文为空,请检查");


                if (!string.IsNullOrEmpty(dp._ErrorMsg))
                {
                    WriteLog(dp._ErrorMsg);
                }
                FeedBackData.Add(dp.Sendbuf);
            }

            return FeedBackData;
        }
        private static void WriteLog(string msg)
        {
            try
            {
                WritLogFile.Log.WriteFile(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff-->") + msg);
            }
            catch
            { }
        }
    }



版权声明:本文为wuyajungogo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。