遗忘海岸

江湖程序员 -Feiph(LM战士)

导航

C# Tcp Server端实现,使用TcpListener

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using F.Studio.Common.Cfg;
using System.Collections.Concurrent;

namespace KomaxCSTcpServer
{
    public class AcquireServer : IDisposable
    {

        private object lockObj = new object();
        public String IP { get; private set; }
        public int Port { get; private set; } //7788
        public String Position { get; set; }
        public TcpListener _Listener = null;
        private bool IsRuning = false;
        private bool _Enabled = false;
        private bool disposed = false;
        public List<ClientDescription> _ClientList = new List<ClientDescription>();
        public event EventHandler<DataReceivedArgs> DataReceived = null;


        public AcquireServer(string ip, int port)
        {
            this.IP = ip;
            this.Port = port;
        }
        public void Start()
        {
            if (_Enabled) return;
            _Enabled = true;

            ThreadPool.QueueUserWorkItem((o) => { _Start(); });

        }
        private void _Start()
        {
            LogInfo("进入工作线程:" + Thread.CurrentThread.ManagedThreadId);
            while (IsRuning)
            {
                Thread.Sleep(1000 * 1);
            }


            try
            {
                _Listener = new TcpListener(IPAddress.Any, Port);
                _Listener.Start();

                // Enter the listening loop.
                while (_Enabled)
                {
                    Console.WriteLine("Waiting for a connection... ");

                    IsRuning = true;
                    // Perform a blocking call to accept requests.
                    // You could also use server.AcceptSocket() here.
                    TcpClient client = _Listener.AcceptTcpClient();
                    Console.WriteLine("Connected!");
                    ThreadPool.QueueUserWorkItem(o => { ReceptionClient(client); }, null);



                }
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }
            finally
            {
                if (_Listener != null)
                {
                    try
                    {
                        Console.WriteLine("关闭监听...");
                        _Listener.Stop();
                    }
                    catch { }
                }
                IsRuning = false;

                if (_Enabled)
                {

                    ThreadPool.QueueUserWorkItem((o) => { _Start(); });
                }

                LogInfo("退出工作线程:" + Thread.CurrentThread.ManagedThreadId);
            }






        }

        private void AddToList(ClientDescription client)
        {
            lock (lockObj)
            {
                if (_ClientList.Any(ent => ent.Equals(client))) return;


                _ClientList.Add(client);

            }
        }
        private void RemoveFromList(ClientDescription client)
        {
            lock (lockObj)
            {
                _ClientList.Remove(client);
            }
        }

        /// <summary>
        /// 发送给全部链接
        /// </summary>
        /// <param name="bytes"></param>
        public void SendToAllClient(byte[] bytes)
        {
            try
            {
                lock (lockObj)
                {
                    foreach (var cd in _ClientList)
                    {
                        if (!cd.IsDead)
                        {
                            cd._Queue4CmdBytes.Enqueue(bytes);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogErr(ex);
            }
        }
        /// <summary>
        /// 发送给最后接入链接
        /// </summary>
        /// <param name="bytes"></param>
        public void SendToLastConnClient(byte[] bytes)
        {

            try
            {

                var cd = _ClientList.OrderByDescending(ent => ent.ConnectedTime).FirstOrDefault();
                if (cd != null)
                {
                    if (!cd.IsDead)
                    {
                        cd._Queue4CmdBytes.Enqueue(bytes);
                    }
                }


            }
            catch (Exception ex)
            {
                LogErr(ex);
            }
        }
        private void ReceptionClient(TcpClient client)
        {
            #region 数据处理
            var cd = new ClientDescription(client);

            cd.RemotePoint = client.Client.RemoteEndPoint as IPEndPoint;
            cd.LocalPoint = client.Client.LocalEndPoint as IPEndPoint;
            cd.ConnectedTime = DateTime.Now;
            cd.LastInterchangeDataTime = DateTime.Now;

            AddToList(cd);

            Byte[] buffer = new byte[1024];
            int errCount = 0;

            var _Stream = client.GetStream();
           


            while (_Enabled && cd._Loop)
            {

                #region Poll
                try
                {

                    #region 数据发送处理

                    if (cd._Queue4CmdBytes.Count > 0)
                    {
                        byte[] bytes = null;
                        if (cd._Queue4CmdBytes.TryDequeue(out bytes))
                        {
                            if (_Stream != null)
                            {
                                _Stream.Write(bytes, 0, bytes.Length);
                                //发送成功更新最后交换时间
                                cd.LastInterchangeDataTime = DateTime.Now;
                                Thread.Sleep(50);
                            }
                        }
                    }


                    #endregion

                    #region 数据接收处理
                    if (_Stream.DataAvailable)
                    {
                        var len = _Stream.Read(buffer, 0, buffer.Length);
                        if (len <= 0) throw new Exception("收到零长度数据!");
                        if (len > 0) cd.LastInterchangeDataTime = DateTime.Now;
                        var bytes = new Byte[len];
                        Array.Copy(buffer, bytes, len);
                        var rawDataStr = Encoding.UTF8.GetString(buffer, 0, len);
                        LogInfo(rawDataStr);
                        if (DataReceived != null)
                        {
                            try
                            {
                                DataReceived(cd, new DataReceivedArgs() { Bytes = bytes, RawStr = rawDataStr,ClientDes=cd });
                            }
                            catch (Exception ex)
                            {
                                LogErr(ex);
                            }
                        }
                        //HandleReceiveStr(bytes, rawDataStr);
                        errCount = 0;
                    }
                    #endregion

                    #region 超时断开链接
                    var maxHoldSeconds = SimpleCfgMgr.GetV<int>("ConnMaxHoldSeconds", 120);
                    var checkConnUseHB = SimpleCfgMgr.GetV<bool>("CheckConnUseHB", true);
                    if ((DateTime.Now - cd.LastInterchangeDataTime).TotalSeconds > maxHoldSeconds)
                    {
                        if (checkConnUseHB)
                        {

                            var bytes_HB = Encoding.UTF8.GetBytes(string.Format("$HB:{0}$", DateTime.Now.Ticks));
                            cd.SendCmd(bytes_HB);

                        }
                        else
                        {
                            cd._Loop = false;
                        }

                    }
                    #endregion



                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    errCount++;
                    if (errCount >= 1)
                    {
                        cd._Loop = false;
                    }

                    LogErr(ex);
                    Thread.Sleep(1000 * 3);
                }
                finally
                {

                }
                #endregion
            }


            //标记成死链接
            cd.IsDead = true;
            #region 尝试关闭链接--这个会通知已经链接的客户端
            try { _Stream.Close(); }
            catch { }
            try { client.Close(); }
            catch { }
            #endregion

            RemoveFromList(cd);
            LogInfo(string.Format("断开与链接{0}:{1}的交互", cd.RemotePoint.Address, cd.RemotePoint.Port));
            #endregion
        }

        public void Stop()
        {
            _Enabled = false;
            if (_Listener != null)
            {

                try { _Listener.Stop(); }
                catch { }
            }

            while (IsRuning)
            {
                Thread.Sleep(1000 * 1);
            }
        }

        #region Log
        private void LogErr(Exception ex)
        {
            if (!SimpleCfgMgr.GetV<bool>("LogErr", true)) return;
            Console.WriteLine(string.Format("[{0}->{1}:{2}] Err:{3}", DateTime.Now.ToString("HH:mm:ss"), IP, Port, ex.Message));
        }

        private void LogInfo(string msg)
        {
            if (!SimpleCfgMgr.GetV<bool>("LogInfo", true)) return;
            Console.WriteLine(string.Format("[{0}->{1}:{2},T:{4}] Info:{3}", DateTime.Now.ToString("HH:mm:ss"), IP, Port, msg, Thread.CurrentThread.ManagedThreadId));
        }

        #endregion


        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, 
        /// releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed 
        /// and unmanaged resources; <c>false</c> 
        /// to release only unmanaged resources.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                    }
                    catch
                    {

                    }
                }

                disposed = true;
            }
        }

        #endregion
    }

    public class DataReceivedArgs : EventArgs
    {
        public ClientDescription ClientDes { get; set; }
        public Byte[] Bytes { get; set; }
        public String RawStr { get; set; }
    }
    public class ClientDescription
    {
        public DateTime ConnectedTime { get; set; }
        public DateTime LastInterchangeDataTime { get; set; }

        public IPEndPoint RemotePoint { get; set; }
        public IPEndPoint LocalPoint { get; set; }
        public String ClientName { get; set; }
        public bool IsDead { get; set; }
        public TcpClient _Client { get; set; }
        public bool _Loop { get; set; }
        private NetworkStream _Stream { get; set; }

        public ConcurrentQueue<byte[]> _Queue4CmdBytes = new ConcurrentQueue<byte[]>();

        public ClientDescription(TcpClient client)
        {
            _Client = client;
            _Stream = client.GetStream();
            _Loop = true;
        }
        public void Close()
        {
            _Loop = false;

        }
        public void SendCmd(byte[] bytes)
        {
            if (!IsDead && _Client != null && _Client.Connected)
            {
                _Queue4CmdBytes.Enqueue(bytes);
            }
        }
    }
}
View Code

 V2版,读写分成2个线程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using F.Studio.Common.Cfg;
using System.Collections.Concurrent;

namespace KomaxCSTcpServer
{
    public class AcquireServerV2 : IDisposable
    {

        private object lockObj = new object();
        public String IP { get; private set; }
        public int Port { get; private set; } //7788
        public String Position { get; set; }
        public TcpListener _Listener = null;
        private bool IsRuning = false;
        private bool _Enabled = false;
        private bool disposed = false;
        public List<ClientDescription> _ClientList = new List<ClientDescription>();
        public event EventHandler<DataReceivedArgs> DataReceived = null;


        public AcquireServerV2(string ip, int port)
        {
            this.IP = ip;
            this.Port = port;
        }
        public void Start()
        {
            if (_Enabled) return;
            _Enabled = true;

            ThreadPool.QueueUserWorkItem((o) => { _Start(); });

        }
        private void _Start()
        {
            LogInfo("进入工作线程:" + Thread.CurrentThread.ManagedThreadId);
            while (IsRuning)
            {
                Thread.Sleep(1000 * 1);
            }


            try
            {
                _Listener = new TcpListener(IPAddress.Any, Port);
                _Listener.Start();

                // Enter the listening loop.
                while (_Enabled)
                {
                    Console.WriteLine("Waiting for a connection... ");

                    IsRuning = true;
                    // Perform a blocking call to accept requests.
                    // You could also use server.AcceptSocket() here.
                    TcpClient client = _Listener.AcceptTcpClient();
                    Console.WriteLine("Connected!");
                    ReceptionClient(client);



                }
            }
            catch (SocketException e)
            {
                if (e.ErrorCode == 10004)
                {
                    //忽略,大概率是关闭服务导致
                }
                else
                {
                    Console.WriteLine("SocketException: {0}", e);
                }
            }
            finally
            {
                if (_Listener != null)
                {
                    try
                    {
                        Console.WriteLine("关闭监听");
                        _Listener.Stop();
                    }
                    catch { }
                }
                IsRuning = false;

                if (_Enabled)
                {

                    ThreadPool.QueueUserWorkItem((o) => { _Start(); });
                }

                LogInfo("退出工作线程:" + Thread.CurrentThread.ManagedThreadId);
            }






        }

        private void AddToList(ClientDescription client)
        {
            lock (lockObj)
            {
                if (_ClientList.Any(ent => ent.Equals(client))) return;


                _ClientList.Add(client);

            }
        }
        private void RemoveFromList(ClientDescription client)
        {
            lock (lockObj)
            {
                _ClientList.Remove(client);
            }
        }

        /// <summary>
        /// 发送给全部链接
        /// </summary>
        /// <param name="bytes"></param>
        public void SendToAllClient(byte[] bytes)
        {
            try
            {
                lock (lockObj)
                {
                    foreach (var cd in _ClientList)
                    {
                        if (!cd.IsDead)
                        {
                            cd._Queue4CmdBytes.Enqueue(bytes);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogErr(ex);
            }
        }
        /// <summary>
        /// 发送给最后接入链接
        /// </summary>
        /// <param name="bytes"></param>
        public void SendToLastConnClient(byte[] bytes)
        {

            try
            {

                var cd = _ClientList.OrderByDescending(ent => ent.ConnectedTime).FirstOrDefault();
                if (cd != null)
                {
                    if (!cd.IsDead)
                    {
                        cd._Queue4CmdBytes.Enqueue(bytes);
                    }
                }


            }
            catch (Exception ex)
            {
                LogErr(ex);
            }
        }
        private void ReceptionClient(TcpClient client)
        {
            #region 数据处理
            var cd = new ClientDescription(client);

            cd.RemotePoint = client.Client.RemoteEndPoint as IPEndPoint;
            cd.LocalPoint = client.Client.LocalEndPoint as IPEndPoint;
            cd.ConnectedTime = DateTime.Now;
            cd.LastInterchangeDataTime = DateTime.Now;

            AddToList(cd);


            //发送线程
            ThreadPool.QueueUserWorkItem(o => { SendHandle(cd); }, null);

            //接收线程
            ThreadPool.QueueUserWorkItem(o => { ReceiveHandle(cd); }, null);
            
            #endregion
        }

        private void ReceiveHandle( ClientDescription cd)
        {
            Byte[] buffer = new byte[1024];
            int errCount = 0;
            while (_Enabled && cd._Loop)
            {

                #region Poll
                try
                {



                    #region 数据接收处理
                    if (cd._Stream.DataAvailable)
                    {
                        var len = cd._Stream.Read(buffer, 0, buffer.Length);
                        if (len <= 0) throw new Exception("收到零长度数据!");
                        if (len > 0) cd.LastInterchangeDataTime = DateTime.Now;
                        var bytes = new Byte[len];
                        Array.Copy(buffer, bytes, len);
                        var rawDataStr = Encoding.UTF8.GetString(buffer, 0, len);
                        LogInfo(rawDataStr);
                        if (DataReceived != null)
                        {
                            try
                            {
                                DataReceived(cd, new DataReceivedArgs() { Bytes = bytes, RawStr = rawDataStr, ClientDes = cd });
                            }
                            catch (Exception ex)
                            {
                                LogErr(ex);
                            }
                        }
                        //HandleReceiveStr(bytes, rawDataStr);
                        errCount = 0;

                        continue;
                    }
                    #endregion

                    #region 超时断开链接
                    var maxHoldSeconds = SimpleCfgMgr.GetV<int>("ConnMaxHoldSeconds", 120);
                    var checkConnUseHB = SimpleCfgMgr.GetV<bool>("CheckConnUseHB", true);
                    if ((DateTime.Now - cd.LastInterchangeDataTime).TotalSeconds > maxHoldSeconds)
                    {
                        if (checkConnUseHB)
                        {

                            var bytes_HB = Encoding.UTF8.GetBytes(string.Format("$HB:{0}$", DateTime.Now.Ticks));
                            cd.SendCmd(bytes_HB);

                        }
                        else
                        {
                            cd._Loop = false;
                        }

                    }
                    #endregion



                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    errCount++;
                    if (errCount >= 1)
                    {
                        cd._Loop = false;
                    }

                    LogErr(ex);
                    Thread.Sleep(1000 * 3);
                }
                finally
                {

                }
                #endregion
            }


            ShutClient(cd);
        }
        private void SendHandle(ClientDescription cd)
        {


            int errCount = 0;
            while (_Enabled && cd._Loop)
            {

                #region Poll
                try
                {
                    #region 数据发送处理

                    if (cd._Queue4CmdBytes.Count > 0)
                    {
                        var sendInterval = SimpleCfgMgr.GetV<int>("SendInterval", 50);
                        byte[] bytes = null;
                        while (cd._Queue4CmdBytes.TryDequeue(out bytes))
                        {
                            if (cd._Stream != null)
                            {
                                cd._Stream.Write(bytes, 0, bytes.Length);
                                //发送成功更新最后交换时间
                                cd.LastInterchangeDataTime = DateTime.Now;
                                if (sendInterval > 0)
                                {
                                    Thread.Sleep(sendInterval);
                                }
                            }
                        }
                    }


                    #endregion

                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    errCount++;
                    if (errCount >= 1)
                    {
                        cd._Loop = false;
                    }

                    LogErr(ex);
                    Thread.Sleep(1000 * 3);
                }
                finally
                {

                }
                #endregion
            }


            ShutClient(cd);
        }

        private void ShutClient(ClientDescription cd)
        {

            if (!cd.IsDead)
            {
                lock (cd)
                {
                    if (!cd.IsDead)
                    {
                        //标记成死链接
                        cd.IsDead = true;
                        #region 尝试关闭链接--这个会通知已经链接的客户端
                        try { cd._Stream.Close(); }
                        catch { }
                        try { cd._Client.Close(); }
                        catch { }
                        #endregion
                    }

                }

                RemoveFromList(cd);
                LogInfo(string.Format("断开与链接{0}:{1}的交互", cd.RemotePoint.Address, cd.RemotePoint.Port));

            }
        }

        public void Stop()
        {
            _Enabled = false;
            if (_Listener != null)
            {

                try { _Listener.Stop(); }
                catch { }
            }

            while (IsRuning)
            {
                Thread.Sleep(1000 * 1);
            }
        }

        #region Log
        private void LogErr(Exception ex)
        {
            if (!SimpleCfgMgr.GetV<bool>("LogErr", true)) return;
            Console.WriteLine(string.Format("[{0}->{1}:{2}] Err:{3}", DateTime.Now.ToString("HH:mm:ss"), IP, Port, ex.Message));
        }

        private void LogInfo(string msg)
        {
            if (!SimpleCfgMgr.GetV<bool>("LogInfo", true)) return;
            Console.WriteLine(string.Format("[{0}->{1}:{2},T:{4}] Info:{3}", DateTime.Now.ToString("HH:mm:ss"), IP, Port, msg, Thread.CurrentThread.ManagedThreadId));
        }

        #endregion


        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, 
        /// releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed 
        /// and unmanaged resources; <c>false</c> 
        /// to release only unmanaged resources.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                    }
                    catch
                    {

                    }
                }

                disposed = true;
            }
        }

        #endregion
    }


}
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections.Concurrent;

namespace KomaxCSTcpServer
{
    public class DataReceivedArgs : EventArgs
    {
        public ClientDescription ClientDes { get; set; }
        public Byte[] Bytes { get; set; }
        public String RawStr { get; set; }
    }
    public class ClientDescription
    {
        public DateTime ConnectedTime { get; set; }
        public DateTime LastInterchangeDataTime { get; set; }

        public IPEndPoint RemotePoint { get; set; }
        public IPEndPoint LocalPoint { get; set; }
        public String ClientName { get; set; }
        public bool IsDead { get; set; }
        public TcpClient _Client { get; set; }
        public bool _Loop { get; set; }
        public NetworkStream _Stream { get; private set; }

        public ConcurrentQueue<byte[]> _Queue4CmdBytes = new ConcurrentQueue<byte[]>();

        public ClientDescription(TcpClient client)
        {
            _Client = client;
            _Stream = client.GetStream();
            _Loop = true;
        }
        public void Close()
        {
            _Loop = false;

        }
        public void SendCmd(byte[] bytes)
        {
            if (!IsDead && _Client != null && _Client.Connected)
            {
                _Queue4CmdBytes.Enqueue(bytes);
            }
        }
    }
}
View Code

 

posted on 2024-08-16 16:57  遗忘海岸  阅读(17)  评论(0编辑  收藏  举报