AgvServer.cs 11.8 KB
using AGVControl;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace BLL
{
    /// <summary>
    /// AGV服务端
    /// </summary>
    public class AgvServer
    {
        private bool _loop;
        private Socket _server;         //服务端
        private List<Client> _client;   //所有客户端
        private Thread tListenClient;   //监听客户端连接
        private const int PORT = 12001;    //端口

        /// <summary>
        /// 节点改变事件
        /// </summary>
        /// <param name="nodeIndex"></param>
        public delegate void NodeChangedEvent(int nodeIndex);
        /// <summary>
        /// 节点改变
        /// </summary>
        public event NodeChangedEvent NodeChanged;
        /// <summary>
        /// 节点在线
        /// </summary>
        public event NodeChangedEvent NodeOnline;

        /// <summary>
        /// AGV服务端
        /// </summary>
        public AgvServer()
        {
            
        }

        /// <summary>
        /// 开启服务
        /// </summary>
        public void Start()
        {
            try
            {
                IPEndPoint localEP = new IPEndPoint(IPAddress.Any, PORT);
                _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _server.Bind(localEP);
                _server.Listen(100);
                Common.log.Info("Server Start");

                _loop = true;
                _client = new List<Client>();
                tListenClient = new Thread(new ThreadStart(ListenClient));
                tListenClient.Start();
            }
            catch (Exception ex)
            {
                Common.log.Error("Start()", ex);
            }
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            _loop = false;
            for (int i = 0; i < _client.Count; i++)
            {
                _client[i].Loop = false;
                _client[i].IsConn = false;
                _client[i].Socket.Close();
            }
            _server.Close();
            _client = null;
            Thread.Sleep(50);
            Common.log.Info("Server Stop");
        }

        public bool ReadyEnter(string nodeName, string rfid = "")
        {
            int idx = FindClient(nodeName);
            if (idx == -1)
            {
                Common.log.Info("ReadyEnter 没有找到" + nodeName);
                return false;
            }
            else
            {
                ClientNode node = new ClientNode(nodeName, rfid, ClientAction.ReadyEnter);
                byte[] buff = Encode(node);
                return Send(idx, buff);
            }
        }

        public bool ReadyLeave(string nodeName, string rfid = "")
        {
            int idx = FindClient(nodeName);
            if (idx == -1)
            {
                Common.log.Info("ReadyLeave 没有找到" + nodeName);
                return false;
            }
            else
            {
                ClientNode node = new ClientNode(nodeName, rfid, ClientAction.ReadyLeave);
                byte[] buff = Encode(node);
                return Send(idx, buff);
            }
        }



        /// <summary>
        /// 监听客户端
        /// </summary>
        private void ListenClient()
        {
            while (_loop)
            {
                try
                {
                    Socket socket = _server.Accept();  //这边会暂停,不需要sleep
                    IPEndPoint ep = (IPEndPoint)socket.RemoteEndPoint;
                    Thread listen = new Thread(new ParameterizedThreadStart(ListenNet));
                    //string ip = ep.Address.ToString();
                    //if (ip == System.Configuration.ConfigurationManager.AppSettings["LocalIP"])
                    //    ip += ":" + ep.Port;

                    //新的客户端
                    Client client = new Client
                    {
                        IP = ep.Address.ToString() + ":" + ep.Port,
                        Loop = true,
                        IsConn = true,
                        Socket = socket,
                        ListenNet = listen,
                        nodeName = new List<string>(),
                    };

                    //重连后关闭旧连接
                    //int idx = _client.FindIndex(s => s.IP.Equals(ip));
                    //if (idx > -1)
                    //{
                    //    _client[idx].IsConn = false;
                    //    _client[idx].nodeName.Clear();
                    //    _client[idx].Loop = false;
                    //    _client[idx].Socket.Close();
                    //    _client.RemoveAt(idx);
                    //}

                    _client.Add(client);
                    listen.Start(_client.Count - 1);
                    Common.log.Info(string.Format("[{0}] 已连接", client.IP));
                }
                catch (SocketException)
                {
                    //关闭连接,退出阻塞Accept
                    Common.log.Info("服务端关闭连接,退出阻塞Accept");
                }
                catch (Exception ex)
                {
                    Common.log.Error("ListenClient()", ex);
                }
            }
        }

        /// <summary>
        /// 客户端数据接收
        /// </summary>
        /// <param name="obj">索引</param>
        private void ListenNet(object obj)
        {
            int sleep = 50;
            Client client = _client[(int)obj];
            byte[] temp = new byte[200];
            int time = 0;

            while (client.Loop)
            {
                Thread.Sleep(sleep);
                try
                {
                    if (!client.Loop) break;
                    if (client.Socket.Available > 0)
                    {
                        time = 0;
                        int count = client.Socket.Receive(temp);
                        byte[] buff = new byte[count];
                        Array.Copy(temp, 0, buff, 0, count);

                        ClientNode node = Decode(buff);
                        if (node == null)
                        {
                            Common.log.Info("解码失败:" + HexBuff(buff));
                        }
                        else
                        {
                            Common.log.Debug("Receive[" + client.IP + "] " + node.ToText());
                            int idx = client.nodeName.FindIndex(s => s == node.Name);
                            if (idx == -1) client.nodeName.Add(node.Name);
                            UpdateNode(node);
                        }
                    }
                    else
                    {
                        time += sleep;
                        if (time > 5000)
                        {
                            Offline(client);
                            Common.log.Info("[" + client.IP + "] 超过5s没有收到数据,关闭连接");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Common.log.Error("ListenNet()", ex);
                }

            }
        }

        /// <summary>
        /// 编码
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private byte[] Encode(ClientNode node)
        {
            int idx = 0;
            byte[] buff = new byte[12];
            buff[idx++] = 0xAD;
            buff[idx++] = (byte)node.Name[0];
            buff[idx++] = Convert.ToByte(node.Name.Substring(1));
            buff[idx++] = (byte)node.RFID[0];
            buff[idx++] = Convert.ToByte(node.RFID.Substring(1));
            buff[idx++] = (byte)node.Action;
            buff[idx++] = 0;
            idx += 4;  //预留
            buff[idx] = 0xDA;
            return buff;
        }

        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="buff"></param>
        /// <returns></returns>
        private ClientNode Decode(byte[] buff)
        {
            int idx = 0;
            if (buff[idx++] != 0xAD) return null;
            string name = (char)buff[idx] + buff[idx + 1].ToString();
            idx += 2;
            string rfid = (char)buff[idx] + buff[idx + 1].ToString();
            idx += 2;
            ClientAction action = (ClientAction)buff[idx++];
            idx += 1;
            idx += 4;  //预留
            if (buff[idx] != 0xDA) return null;

            ClientNode node = new ClientNode(name, rfid, action);
            return node;
        }

        private void UpdateNode(ClientNode node)
        {
            int idx = Common.nodeInfo.FindIndex(s => s.Name == node.Name);
            if (idx == -1)
            {
                Common.log.Info("UpdateNode " + node.Name + " 不存在");
                return;
            }

            if (!Common.nodeInfo[idx].Online)
            {
                Common.nodeInfo[idx].Online = true;
                NodeOnline?.Invoke(idx);
            }

            if (Common.nodeInfo[idx].Action != node.Action ||
                Common.nodeInfo[idx].RFID != node.RFID)
            {
                Common.nodeInfo[idx].Action = node.Action;
                Common.nodeInfo[idx].RFID = node.RFID;
                Common.log.Info(node.Name + "更新 " + node.ToText());
                NodeChanged?.Invoke(idx);
            }
        }

        private void Offline(Client client)
        {
            client.Loop = false;
            client.IsConn = false;
            client.Socket.Close();

            for (int i = 0; i < client.nodeName.Count; i++)
            {
                int idx = Common.nodeInfo.FindIndex(s => s.Name == client.nodeName[i]);
                if (idx == -1) continue;
                Common.nodeInfo[idx].Offline();
                NodeChanged(idx);
                NodeOnline(idx);
            }
            client.nodeName.Clear();
            _client.Remove(client);
        }

        /// <summary>
        /// 16进制
        /// </summary>
        /// <param name="buff"></param>
        /// <returns></returns>
        private string HexBuff(byte[] buff)
        {
            string s = "";
            if (buff == null) return s;

            for (int i = 0; i < buff.Length; i++)
                s += buff[i].ToString("X2") + " ";
            return s;
        }

        /// <summary>
        /// 查找客户端
        /// </summary>
        /// <param name="name">节点名称</param>
        /// <returns></returns>
        private int FindClient(string name)
        {
            int index = -1;

            for (int i = 0; i < _client.Count; i++)
            {
                if (_client[i].IsConn)
                {
                    int idx = _client[i].nodeName.FindIndex(a => a == name);
                    if (idx != -1)
                    {
                        index = i;
                        break;
                    }
                }
            }

            return index;
        }

        /// <summary>
        /// 发送命令
        /// </summary>
        /// <param name="idx"></param>
        /// <param name="buff"></param>
        /// <returns></returns>
        private bool Send(int idx, byte[] buff)
        {
            string ip = "[" + _client[idx].IP + "]";

            if (!_client[idx].IsConn)
            {
                Common.log.Info(ip + " 没有连接");
                return false;
            }

            try
            {
                _client[idx].Socket.Send(buff);
                Common.log.Debug("SendTo" + ip + ": " + HexBuff(buff));
                return true;
            }
            catch (Exception ex)
            {
                Common.log.Error("Send" + ip, ex);
                return false;
            }
        }

    }

}