Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何解决.NET套接字和TCP可能出现的数据包丢失问题?_.net_Sockets - Fatal编程技术网

如何解决.NET套接字和TCP可能出现的数据包丢失问题?

如何解决.NET套接字和TCP可能出现的数据包丢失问题?,.net,sockets,.net,Sockets,我需要一些帮助,了解如何使用.NET套接字通过TCP进行大容量数据馈送来解决我遇到的问题 简而言之,当客户端应用程序启动时,它会连接到服务器上的特定端口。一旦连接,服务器开始向客户机发送实时数据,客户机将在类似股票行情的UI中显示信息。服务器支持多个客户端工作站,因此数据将通过多个端口(多个套接字)发送 一切都是实施和工作的速度慢,饲料和低容量伟大。我正在对系统进行压力测试,以确保灵活性和可伸缩性。当我增加频率时,服务器运行良好。然而,我看到客户端上似乎丢失了数据包。这是随机发生的 目前,广播的

我需要一些帮助,了解如何使用.NET套接字通过TCP进行大容量数据馈送来解决我遇到的问题

简而言之,当客户端应用程序启动时,它会连接到服务器上的特定端口。一旦连接,服务器开始向客户机发送实时数据,客户机将在类似股票行情的UI中显示信息。服务器支持多个客户端工作站,因此数据将通过多个端口(多个套接字)发送

一切都是实施和工作的速度慢,饲料和低容量伟大。我正在对系统进行压力测试,以确保灵活性和可伸缩性。当我增加频率时,服务器运行良好。然而,我看到客户端上似乎丢失了数据包。这是随机发生的

目前,广播的每条消息的开头都有一个4字节的值,用于标识该消息的长度。当我们在客户机中接收数据时,我们将数据附加到缓冲区(流)中,直到我们接收到该数量的字节。任何附加字节都将被视为下一条消息的开始。同样,在我把频率调高之前,这很有效

在我的测试中,我发送了一个大约225字节的数据包,然后是一个大约310kB的数据包和另一个大约40kb的数据包。每1秒发送一条消息不会失败,大约有12个客户端正在运行。将频率增加到1/2秒,我最终看到客户机的一个显示冻结。到1/4秒,我可以在几秒钟内用4个客户端重现问题

查看我的代码(如果需要,我可以提供),我看到所有客户机都在接收数据,但不知何故,信息“不同步”,预期长度值非常大(在1亿范围内)。结果,我们只是不断地阅读数据,永远也感觉不到信息的结尾

我需要一种更好的方法或方法来确保我得到了预期的数据,并且不会丢失数据包。你能帮忙吗

更新

我做了大量额外的测试,改变了消息的大小和传递频率。这肯定是有关联的。消息的大小越小,频率就越高。但是,不可避免地,我总是能够打破它

因此,要更准确地描述我正在寻找的是:

  • 了解正在发生的事情。这将帮助我确定一个可能的解决方案,或者至少为可靠的行为建立阈值

  • 实现一个故障安全机制,这样当问题发生时,我可以处理它,并可能从中恢复。可能是在数据流中添加校验和之类的东西

  • 以下是我在客户端(接收)应用程序中运行的代码:

    public void StartListening(SocketAsyncEventArgs e)
    {
        e.Completed += SocketReceive;
        socket.ReceiveAsync(e);
    }
    
    private void SocketReceive(Object sender, SocketAsyncEventArgs e)
    {
        lock (_receiveLock)
        {
            ProcessData(e.Buffer, e.BytesTransferred);
    
            socket.ReceiveAsync(e);
        }
    }
    
    private void ProcessData(Byte[] bytes, Int32 count)
    {
        if (_currentBuffer == null)
            _currentBuffer = new ReceiveBuffer();
    
        var numberOfBytesRead = _currentBuffer.Write(bytes, count);
    
        if (_currentBuffer.IsComplete)
        {
            // Notify the client that a message has been received (ignore zero-length, "keep alive", messages)
            if (_currentBuffer.DataLength > 0)
                NotifyMessageReceived(_currentBuffer);
    
            _currentBuffer = null;
    
            // If there are bytes remaining from the original message, recursively process
            var numberOfBytesRemaining = count - numberOfBytesRead;
    
            if (numberOfBytesRemaining > 0)
            {
                var remainingBytes = new Byte[numberOfBytesRemaining];
                var offset = bytes.Length - numberOfBytesRemaining;
    
                Array.Copy(bytes, offset, remainingBytes, 0, numberOfBytesRemaining);
    
                ProcessData(remainingBytes, numberOfBytesRemaining);
            }
        }
    }
    
    
    internal sealed class ReceiveBuffer
    {
        public const Int32 LengthBufferSize = sizeof(Int32);
    
        private MemoryStream _dataBuffer = new MemoryStream();
        private MemoryStream _lengthBuffer = new MemoryStream();
    
        public Int32 DataLength { get; private set; }
    
        public Boolean IsComplete
        {
            get { return (RemainingDataBytesToWrite == 0); }
        }
    
        private Int32 RemainingDataBytesToWrite
        {
            get
            {
                if (DataLength > 0)
                    return (DataLength - (Int32)_dataBuffer.Length);
    
                return 0;
            }
        }
    
        private Int32 RemainingLengthBytesToWrite
        {
            get { return (LengthBufferSize - (Int32)_lengthBuffer.Length); }
        }
    
        public Int32 Write(Byte[] bytes, Int32 count)
        {
            var numberOfLengthBytesToWrite = Math.Min(RemainingLengthBytesToWrite, count);
    
            if (numberOfLengthBytesToWrite > 0)
                WriteToLengthBuffer(bytes, numberOfLengthBytesToWrite);
    
            var remainingCount = count - numberOfLengthBytesToWrite;
    
            // If this value is > 0, then we have still have more bytes after setting the length so write them to the data buffer
            var numberOfDataBytesToWrite = Math.Min(RemainingDataBytesToWrite, remainingCount);
    
            if (numberOfDataBytesToWrite > 0)
                _dataBuffer.Write(bytes, numberOfLengthBytesToWrite, numberOfDataBytesToWrite);
    
            return numberOfLengthBytesToWrite + numberOfDataBytesToWrite;
        }
    
        private void WriteToLengthBuffer(Byte[] bytes, Int32 count)
        {
            _lengthBuffer.Write(bytes, 0, count);
    
            if (RemainingLengthBytesToWrite == 0)
            {
                var length = BitConverter.ToInt32(_lengthBuffer.ToArray(), 0);
    
                DataLength = length;
            }
        }
    }
    

    没有看到你的代码,我们只能猜测。我的猜测是:您是否在考虑读取少于完整4字节头的情况?您可能只读取其中的一个、两个或三个字节。数据量越大,这种情况发生的频率越高

    由于TCP是一种可靠的协议,这不是由于数据包丢失造成的。任何丢失的数据包都会导致以下两种情况之一:

  • 丢失的数据将被重新传输,接收器会经历短暂的暂停,但不会看到丢失的数据或数据出现故障
  • 插座是关着的
  • 更新


    将部分长度写入缓冲区后,您的
    IsComplete
    方法返回
    true
    。这会导致
    ProcessData()
    中的接收器代码丢弃已接收到的长度缓冲区字节,然后失去同步。

    我不知道您是否听说过它,这似乎至少是您的问题的一部分。如果您查看了当数据进入时正在执行的调用的数量(读取:您的ProcessData方法)。它正在阻止服务器中的所有其他内容,而它拥有控制权,甚至递归地工作

    这意味着您必须处理的数据越大,此方法返回的时间就越长。在此期间,您不能处理其他传入消息。因此,本地NIC的缓冲区会被填满,任何涉及路由器的路由器都会为您缓冲数据包,等等。如果你不能读得更快,数据包会被丢弃并重新发送,你的网络也会被阻塞。这被称为上述网络拥塞

    在你的代码中,另一个直接跳到我身上的东西是锁。在异步工作时,究竟为什么要锁定任何东西?您必须了解SAEA对象是处理异步方法调用的线程的stateobject。这是为了消除自己穿线的痛苦。您基本上调用sockets ReceiveAsync方法并向其抛出一个SAEA对象,如果处理完成,则从中获取缓冲区和信息并再次将其返回到ReceiveAsync方法。处理在另一个与从套接字读取无关的方法中进行。这样你可以保持你的插座快速


    最后一点:我不知道应用程序的用途是什么,但通常不鼓励使用TCP处理高速传入的高负载数据。这就是为什么更快的游戏网络引擎使用UDP。即使是速度较慢的引擎,通常每秒也会发送20个数据包。如果你的代码在半秒钟内中断,你应该考虑切换到UDP。我发现这是一个关于使用UDP进行实时联网的良好信息来源。正如他解释的概念,它可能对您也有用。

    错误可能在您对预期长度的计算中。向我们展示codezDoubtful,因为今天下午代码可以完美地工作一个多小时,有12个客户端,数据每秒输出一次。我一提高频率,它就失败了。相同的代码,相同的计算-这只是BitConverter.ToInt32(lengthData)。这段代码非常糟糕。更多