C#问题发送和接收数据

问题描述

我知道这是一个讨论非常多的话题,但是我的代码遇到了奇怪的行为。

进行一些测试,我发现对于某些客户端来说一切都很好,但是其他客户端根本无法通过基于TCPClient自定义客户端设计来接收和发送数据。 尽管许多用户都可以通过此连接类型访问我的服务器,但我无法确认此问题是由VPN还是NATs连接引起的。

我一直在阅读.Net中的TCPClientTCPListener搜索诸如我的问题但没有运气。我得到的一切都是可怜的例子。 我将不胜感激,甚至会为网络高级编程提供参考。

这是我的代码。最新最稳定

Cliente.cs

using System;
using System.Collections.Generic;
using System.Net.networkinformation;
using System.Net.sockets;
using System.Net;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.Linq;
using System.IO.Compression;

namespace netComunicator
{
    public class Client:Idisposable
    {
        int BufferSize { get { return 16384; } }

        /// <summary>
        /// .NET TcpClient for receive and send methods
        /// </summary>
        public TcpClient NetClient = new TcpClient();


        /// <summary>
        /// Externl buffer to store incoming data
        /// This buffers get clear when EOS secuence is present on it
        /// </summary>
        List<byte> ExternBuffer = new List<byte>();
        

        /// <summary>
        /// Remote port
        /// </summary>
        public string Port { get; set; }


        /// <summary>
        /// MAC address from client
        /// </summary>
        public string ClientMac { get; set; }


        /// <summary>
        /// Client IP
        /// </summary>
        public string ClientIp { get; set; }


        /// <summary>
        /// Cifrado
        /// Use NETSID as public key and his first 128 bits as IV
        /// </summary>
        private NetCipher Cipher { get; set; }

        
        /// <summary>
        /// Shared network session id
        /// </summary>
        public string NETSID { get; set; }


        #region delegados y eventos
        public delegate void NoConnection(string noConnectedClient);
        public delegate void ObjectDataReceived(object data,Client client);
        public delegate void Clientdisconnected(Client client);

        public event Clientdisconnected OnClientdisconnected;
        public event ObjectDataReceived OnObjectDataReceived;
        public event NoConnection OnFailConnectTo;
        #endregion

        public NetworkStream NetStream;

        CancellationTokenSource CTS;
        CancellationToken Token;

        CancellationTokenSource CancelKAS;
        CancellationToken CancelKASToken;



        /// <summary>
        /// Max lost count of KEEP_ALIVE
        /// </summary>
        const int MAX_KEEP_ALIVE_COUNT = 30;

        /// <summary>
        /// Current lost KEEP_ALIVE_SIGNAL
        /// </summary>
        int CURRENT_KEEP_ALIVE_SIGNAL_COUNT = 0;

        public Client(byte[] NETSID)
        {
            CTS = new CancellationTokenSource();
            Token = CTS.Token;

            CancelKAS = new CancellationTokenSource();
            CancelKASToken = CancelKAS.Token;

            ClientMac = GetMac();

            if (NETSID != null)
            {
                Cipher = new NetCipher(NETSID);
                this.NETSID = new Guid(NETSID).ToString();
            }
        }


        public void StartClient()
        {
            try
            {
                Task.Factory.StartNew(() => Receive(),Token);
            }
            catch { }
        }

        public void StopClient()
        {
            CTS.Cancel();
        }

        public void StartKeepAliveSignal()
        {
            Task.Factory.StartNew(() =>
            { 
                while (!CancelKASToken.IsCancellationRequested)
                {
                    if (CURRENT_KEEP_ALIVE_SIGNAL_COUNT == MAX_KEEP_ALIVE_COUNT)
                    {
                        OnClientdisconnected?.BeginInvoke(this,null,null);
                        dispose();
                    }

                    Send("KEEP_ALIVE");
                    CURRENT_KEEP_ALIVE_SIGNAL_COUNT++;

                    Thread.Sleep(1000);
                }
            },CancelKASToken);
        }

        public void StoptKeepAliveSignal()
        {
            CancelKAS.Cancel();
        }
        

        static string GetLocalIPAddress()
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                    return ip.ToString();
            throw new Exception("No network adapters with an IPv4 address in the system!");
        }

        string GetMac()
        {
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            var mac = nics.Where(n => n.OperationalStatus == OperationalStatus.Up).FirstOrDefault();
            if (mac != null)
                return mac.GetPhysicalAddress().ToString();
            return "";
        }
        

        void CloseConnection()
        {
            NetClient.Close();
        }
        
        public void dispose()
        {
            try
            {
                StoptKeepAliveSignal();
                StopClient();
                CloseConnection();
            }
            catch{ }
        }
        

        async public Task<bool> Connect(string ip,int port,bool initKAS = true)
        {
            return await Task.Factory.StartNew(() =>
            {
                try
                {
                    NetClient.Connect(ip,port);

                    Guid guid = new Guid(NETSID);

                    if (NetStream == null)
                    {
                        NetStream = NetClient.GetStream();
                        Cipher = new NetCipher(guid.ToByteArray());
                    }

                    List<byte> initdata = new List<byte>();
                    initdata.AddRange(NetComTools.wellcomeMsg);
                    initdata.AddRange(System.Text.Encoding.ASCII.GetBytes(ClientMac));
                    initdata.AddRange(guid.ToByteArray());
                    
                    NetStream.Write(initdata.ToArray(),initdata.Count);

                    StartClient();

                    // if required KEEP_ALIVE_SIGNAL on
                    if (initKAS)
                        StartKeepAliveSignal();

                    ClientIp = ip;

                    return true;
                }
                catch
                {
                    // Notificar que no se pudo establecer conexion
                    OnFailConnectTo?.Invoke(ip);
                }
                return false;
            });
        }
        
        public void Receive()
        {
            while (!Token.IsCancellationRequested)
            {
                try
                {
                    byte[] buff = new byte[BufferSize];
                    int bytesReaded = NetStream.Read(buff,buff.Length);
                    byte[] bytesFromBuffer = buff.Take(bytesReaded).ToArray();

                    CURRENT_KEEP_ALIVE_SIGNAL_COUNT = 0;

                    ExternBuffer.AddRange(bytesFromBuffer);

                    // Determine if current received bytes have End Of Secuence byte array
                    bool iSEOS = IsEndOfSecuence(ExternBuffer);

                    if (iSEOS)
                    {
                        // Secuence separator takes inside EOS and passing ExternBuffer
                        // split current buffer in N subsecuences.
                        // This because in one buffer read,can be more than one message delimited by EOS
                        List<byte[]> secuences = SecuenceSeparator(ExternBuffer);

                        ExternBuffer.Clear();

                        foreach (byte[] secuence in secuences)
                        {
                            byte[] decompress = Decompress(secuence);
                            byte[] decipher = Cipher.Decrypt(decompress);
                            object data = Serializer.Deserialize(decipher);
                            OnObjectDataReceived?.BeginInvoke(data,this,null);
                        }
                    }
                }
                catch
                {
                    dispose();
                    OnClientdisconnected?.Invoke(this);
                    return;
                }

                Thread.Sleep(10);
            }
        }

        /// <summary>
        /// If bytes[] have an EOS secuence return true
        /// </summary>
        bool IsEndOfSecuence(byte[] bytes)
        {
            int secuencelen = bytes.Length - 1;
            int checkSum = NetComTools.EOS.Length - 1;
            int EOSLen = checkSum;
            int trys = 0;

            for (int i = secuencelen; i >= 0; i--)
            {
                if (trys <= EOSLen)
                {
                    if (checkSum == 0)
                        return true;
                    if (bytes[i] == NetComTools.EOS[checkSum])
                        checkSum--;
                    else
                        checkSum = NetComTools.EOS.Length - 1;
                }
                else
                    return false;

                trys++;
            }
            return false;
        }
        bool IsEndOfSecuence(List<byte> bytes)
        {
            int secuencelen = bytes.Count - 1;
            int checkSum = NetComTools.EOS.Length - 1;
            int EOSLen = checkSum;
            int trys = 0;

            for (int i = secuencelen; i >= 0; i--)
            {
                if (trys <= EOSLen)
                {
                    if (checkSum == 0)
                        return true;
                    if (bytes[i] == NetComTools.EOS[checkSum])
                        checkSum--;
                    else
                        checkSum = NetComTools.EOS.Length - 1;
                }
                else
                    return false;

                trys++;
            }
            return false;
        }
        

        List<byte[]> SecuenceSeparator(byte[] data)
        {
            List<byte[]> subsecuences = new List<byte[]>();
            List<byte> externBuff = new List<byte>(data);

            int inc = 0;
            int secuencelen = externBuff.Count;
            int lastpos = 0;
            //40  =  15 + datos,5 + eos,15 + datos,5 + eos
            for (int i = 0; i < secuencelen; i++)
            {
                if (externBuff[i] == NetComTools.EOS[inc])
                {
                    inc++;
                    if (inc == NetComTools.EOS.Length)
                    {
                        List<byte> sub_nsecuence = new List<byte>();
                        int elements = i + 1 - lastpos - NetComTools.EOS.Length;
                        byte[] matchsecuence = new byte[elements];
                        externBuff.copyTo(lastpos,matchsecuence,elements);
                        sub_nsecuence.AddRange(matchsecuence);
                        subsecuences.Add(sub_nsecuence.ToArray());
                        inc = 0;
                        lastpos = i + 1;
                    }
                }
                else
                    inc = 0;

            }
            return subsecuences;
        }
        List<byte[]> SecuenceSeparator(List<byte> externBuff)
        {
            List<byte[]> subsecuences = new List<byte[]>();

            int inc = 0;
            int secuencelen = externBuff.Count;
            int lastpos = 0;

            for (int i = 0; i < secuencelen; i++)
            {
                if (externBuff[i] == NetComTools.EOS[inc])
                {
                    inc++;
                    if (inc == NetComTools.EOS.Length)
                    {
                        List<byte> sub_nsecuence = new List<byte>();
                        int elements = i + 1 - lastpos - NetComTools.EOS.Length;
                        byte[] matchsecuence = new byte[elements];
                        externBuff.copyTo(lastpos,elements);
                        sub_nsecuence.AddRange(matchsecuence);
                        subsecuences.Add(sub_nsecuence.ToArray());
                        inc = 0;
                        lastpos = i + 1;
                    }
                }
                else
                    inc = 0;

            }
            return subsecuences;
        }
        
        public void Send(object data)
        {
            try
            {
                byte[] objDatabyte = Serializer.Serialize(data);
                byte[] cipher = Cipher.Encrypt(objDatabyte);
                byte[] compressed = Compress(cipher);
                NetStream.Write(compressed,compressed.Length);
                NetStream.Write(NetComTools.EOS,NetComTools.EOS.Length);
            }
            catch
            {
                OnClientdisconnected?.Invoke(this);
                dispose();
            }
        }

        public static byte[] Compress(byte[] raw)
        {
            using (MemoryStream msw = new MemoryStream())
            {
                using (GZipStream gzip = new GZipStream(msw,CompressionMode.Compress))
                    gzip.Write(raw,raw.Length);
                return msw.ToArray();
            }
        }

        public static byte[] Decompress(byte[] gzipraw)
        {
            using (GZipStream msw = new GZipStream(new MemoryStream(gzipraw),CompressionMode.Decompress))
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    int readed;
                    while ((readed = msw.ReadByte()) != -1)
                        ms.WriteByte((byte)readed);
                    return ms.ToArray();
                }
            }
        }
    }

    static class Serializer
    {
        public static byte[] Serialize(object anySerializableObject)
        {
            using (var memoryStream = new MemoryStream())
            {
                (new BinaryFormatter()).Serialize(memoryStream,anySerializableObject);
                return memoryStream.ToArray();
            }
        }

        public static object Deserialize(byte[] message)
        {
            using (var memoryStream = new MemoryStream(message))
            {
                BinaryFormatter b = new BinaryFormatter();
                memoryStream.Position = 0;
                return b.Deserialize(memoryStream);
            }

        }
    }
}

Server.cs

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.sockets;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Threading;
using System.Linq;
namespace netComunicator
{
    public class Server
    {
        /// <summary>
        /// Connected Clients
        /// </summary>
        public ConcurrentBag<Client> Clients = new ConcurrentBag<Client>();
        

        /// <summary>
        /// .NET TcpListenet
        /// </summary>
        public TcpListener Host;


        CancellationTokenSource CTS;
        CancellationToken Token;


        #region Delegados y Eventos
        public delegate void ClientConnected(Client client);
        public delegate void Clientdisconnected(Client client);

        public event ClientConnected OnClientConnected;
        public event Clientdisconnected OnClientdisconnected;
        #endregion

        
        public Server(int port)
        {
            CTS = new CancellationTokenSource();
            Token = CTS.Token;
            try
            {
                Host = new TcpListener(IPAddress.Parse(NetComTools.thisClientIP),port);
                Host.Start();

                try  { Task.Factory.StartNew(() => AcceptIncoming(),Token); }  catch (Exception ex) {
                    throw ex;
                }
            }
            catch (Exception ec)
            {
                throw ec;
            }
        }
        

        public void SendTo(Client client,object data)
        {
            Client cl = Clients.Where(c => c.Equals(client)).FirstOrDefault();
            cl?.Send(data);
        }


        public void SendAll(object data)
        {
            Task.Factory.StartNew(() =>
            {
                foreach (Client client in Clients)
                    client.Send(data);
            });
        }

        
        void AcceptIncoming()
        {
            while (!Token.IsCancellationRequested)
            {
                try
                {
                        AsyncCallback acb = new AsyncCallback(PerformConnection);
                        Host.BeginAcceptSocket(acb,null);

                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    throw ex;
                }

            }
        }

        void PerformConnection(IAsyncResult res)
        {
            TcpClient tempClient = null;
            try
            {
                tempClient = Host.EndAcceptTcpClient(res);
                NetworkStream ns;
                ns = tempClient.GetStream();

                byte[] initData = new byte[NetComTools.wellcomeMsg.Length + 28];

                ns.Read(initData,initData.Length);
                
                byte[] wellcome = new byte[NetComTools.wellcomeMsg.Length];
                byte[] mac = new byte[12];
                byte[] netsidfromclient = new byte[16];
                List<byte> ini = new List<byte>(initData);
                ini.copyTo(0,wellcome,4);
                ini.copyTo(4,mac,12);
                ini.copyTo(16,netsidfromclient,16);

                if (WellcomeOk(wellcome))
                {
                    
                    Client newClient = new Client(netsidfromclient)
                    {
                        ClientIp = tempClient.Client.RemoteEndPoint.ToString().Split(':')[0],Port = tempClient.Client.RemoteEndPoint.ToString().Split(':')[1],NetStream = ns,ClientMac = System.Text.Encoding.ASCII.GetString(mac),};
                    
                    Clients.Add(newClient);
                    newClient.NetClient = tempClient;
                    newClient.OnClientdisconnected += newClient_OnClientdisconnected;
                    newClient.StartClient();
                    OnClientConnected?.BeginInvoke(newClient,null);
                }
                else
                    tempClient.Close();
                
            }
            catch {if( tempClient != null) tempClient.Close(); return; }
        }

        bool WellcomeOk(byte[] wellcomeFromNet)
        {
            if (wellcomeFromNet.Length != NetComTools.wellcomeMsg.Length)
                return false;
            else
            {
                for (int i = 0; i < wellcomeFromNet.Length; i++)
                    if (wellcomeFromNet[i] != NetComTools.wellcomeMsg[i])
                        return false;
            }
            return true;
        }



        void newClient_OnClientdisconnected(Client client)
        {
            client.OnClientdisconnected -= newClient_OnClientdisconnected;
            Clients = RemoveClientFromList(client);
            OnClientdisconnected?.Invoke(client);
        }


        ConcurrentBag<Client> RemoveClientFromList(Client client)
        {
            ConcurrentBag<Client> Acl = new ConcurrentBag<Client>();
            return new ConcurrentBag<Client>(Clients.Where(c => c != client));
        }


        public void StopListener()
        {
            Host.Stop();
            CTS.Cancel();
        }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)