如何解决可能的信息包丢失问题.NET套接字和TCP?如何解决、问题、信息、TCP

2023-09-05 01:09:37 作者:旧时光

我需要一些帮助找出如何解决问题,我有一个大容量的数据馈送使用.NET插座目睹了TCP。

在简单地说,客户端应用程序启动时,它连接到服务器上的特定端口。一旦连接,服务器开始发送实时数据,这些数据显示在一个代码状的UI的信息的客户端。该服务器支持多个客户端工作站,因此数据将通过多个端口(多接口)发送。

一切都实现,并与一个缓慢的饲料和小批量伟大的工作。我压力测试制度,确保resiliance和可扩展性。当我提高频率,服务器完美运行。但是,我看到什么出现在客户端上丢失的数据包。这发生在随机时间

目前,每个消息被广播是pfaced具有一个4字节的值,它标识该消息的长度$ P $。由于我们在客户端接收数据,将数据追加到缓冲区(流),直到我们收到的字节数。任何额外的字节被认为是下一个信息的开始。同样,这个伟大工程,直到我打开了的频率。

TCP IP网络编程 Linux系统下的TCP套接字编程

在我的测试,我送一包约225个字节,后面是一个约310KB,另一个40KB左右。发送一条消息,每1秒的作品,而不带约12客户机上运行失败。增加频率至1/2秒,我终于看到了客户端的显示冻结之一。将1/4秒,我可以用少至4个客户在几秒钟内重现该问题。

看着我的code(我可以提供,如果需要的话),我看到所有的客户端都接收数据,但不知何故信息跌失同步和预期的长度值是巨大的(在100亿美元之间)。这样一来,我们就继续读数据,而不会察觉到邮件的末尾。

我要么需要一个更好的方法或方式,以确保我得到我预期的数据并没有丢失数据包。你能帮忙吗?

更新

我已经做了一吨的额外的测试,不同的消息和配送频率的大小。肯定是有相关性。越小我做邮件大小,频率,我可以达到更高。但是,不可避免的是,我总是能打破它。

所以,为了更准确地描述我所期待的是:

要明白发生了什么。这将帮助我找出一个可行的解决方案,或者至少,建立门槛可靠的行为。

实现故障安全机制,以便出现问题时,我能应付,并可能从中恢复。也许增加一个校验和到数据流或类似的东西。

下面是我在客户机正在运行的code(接收)的应用:

 公共无效StartListening(的SocketAsyncEventArgs E)
{
    e.Completed + = SocketReceive;
    socket.ReceiveAsync(E);
}

私人无效SocketReceive(对象发件人,让SocketAsyncEventArgs E)
{
    锁定(_receiveLock)
    {
        过程数据(e.Buffer,e.BytesTransferred);

        socket.ReceiveAsync(E);
    }
}

私人无效过程数据(字节[]字节的Int32计数)
{
    如果(_currentBuffer == NULL)
        _currentBuffer =新ReceiveBuffer();

    VAR numberOfBytesRead = _currentBuffer.Write(字节数);

    如果(_currentBuffer.IsComplete)
    {
        //通知该消息已被接收到的客户机(忽略零长度,保持活动,消息)
        如果(_currentBuffer.DataLength大于0)
            NotifyMessageReceived(_currentBuffer);

        _currentBuffer = NULL;

        //如果有从原始邮件剩余字节,递归过程
        VAR numberOfBytesRemaining =计数 -  numberOfBytesRead;

        如果(numberOfBytesRemaining大于0)
        {
            VAR remainingBytes =新的字节[numberOfBytesRemaining]
            无功补偿= bytes.Length  -  numberOfBytesRemaining;

            Array.Copy(字节,胶印,remainingBytes,0,numberOfBytesRemaining);

            过程数据(remainingBytes,numberOfBytesRemaining);
        }
    }
}


内部密封类ReceiveBuffer
{
    公共常量的Int32 LengthBufferSize = sizeof的(Int32)已;

    私人MemoryStream的_dataBuffer =新的MemoryStream();
    私人MemoryStream的_lengthBuffer =新的MemoryStream();

    公众的Int32数据长度{获得;私定; }

    公共布尔IsComplete
    {
        {返回(RemainingDataBytesToWrite == 0); }
    }

    私人的Int32 RemainingDataBytesToWrite
    {
        得到
        {
            如果(数据长度大于0)
                返程(数据长度 - (Int32)已_dataBuffer.Length);

            返回0;
        }
    }

    私人的Int32 RemainingLengthBytesToWrite
    {
        {返回(LengthBufferSize  - (Int32)已_lengthBuffer.Length); }
    }

    公众的Int32写入(字节[]字节的Int32计数)
    {
        VAR numberOfLengthBytesToWrite = Math.Min(RemainingLengthBytesToWrite,计数);

        如果(numberOfLengthBytesToWrite大于0)
            WriteToLengthBuffer(字节,numberOfLengthBytesToWrite);

        VAR remainingCount =计数 -  numberOfLengthBytesToWrite;

        //如果此值是GT; 0,那么我们仍然设置长度,因此写入到数据缓冲区之后有更多的字节
        VAR numberOfDataBytesToWrite = Math.Min(RemainingDataBytesToWrite,remainingCount);

        如果(numberOfDataBytesToWrite大于0)
            _dataBuffer.Write(字节,numberOfLengthBytesToWrite,numberOfDataBytesToWrite);

        返回numberOfLengthBytesToWrite + numberOfDataBytesToWrite;
    }

    私人无效WriteToLengthBuffer(字节[]字节的Int32计数)
    {
        _lengthBuffer.Write(字节,0,计数);

        如果(RemainingLengthBytesToWrite == 0)
        {
            变种长度= BitConverter.ToInt32(_lengthBuffer.ToArray(),0);

            数据长度=长度;
        }
    }
}
 

解决方案

没有看到你的code,我们只能猜测。我的猜测是:您是否正在考虑的情况下,你读的小于的全部4个字节的头?你可能只读它的一个,两个或三个字节。更高的数据量会导致这种情况更经常发生。

由于TCP是一个可靠的协议,这是的没有的因数据包丢失。任何丢失的数据包导致两种情况之一发生:

在丢失的数据重发和接收器经历了一个短暂的停顿,但从来没有看到丢失数据或数据不正常。 在套接字被关闭。

更新

IsComplete 方法的返回值后部分长度已被写入缓冲区。这将导致你的接收机code。在过程数据()丢弃已收到,然后获取不同步。长度缓冲区的字节

I need some help figuring out how to troubleshoot a problem I am witnessing with a high-volume data feed over TCP using .NET sockets.

In a nutshell, when the client application starts, it connects to a specific port on the server. Once connected, the server begins sending real-time data to the client which displays the information in a ticker-like UI. The server supports multiple client workstations, so data will be sent via multiple ports (multiple sockets).

Everything is implemented and working great with a slow feed and low-volume. I am stress testing the system to ensure resiliance and scalability. When I increase the frequency, the server runs perfectly. However, I am seeing what appears to be lost packets on the clients. This occurs at random times.

Currently, each message that is broadcast is prefaced with a 4-byte value identifying the length of that message. As we are receiving data in the client, we append the data to a buffer (Stream) until we receive that number of bytes. Any additional bytes are considered the start of the next message. Again, this works great until I turn up the frequency.

In my test, I send a packet of approx 225 bytes, followed by one of approx 310kB and another around 40kb. Sending a message every 1 second works without fail with about 12 clients running. Increasing the frequency to 1/2 second, I eventually saw one of the client's displays freeze. Going to 1/4 second and I can reproduce the problem with as few as 4 clients within a few seconds.

Looking at my code (which I can provide, if needed), I see that all of the clients are receiving data but somehow the information fell 'out-of-sync' and the expected length value is enormous (in the 100 million range). As a result, we just keep reading data and never perceive the end of the message.

I either need a better approach or a way to ensure I'm getting the data I expect and not losing packets. Can you help?

UPDATE

I've done a ton of additional testing, varying the size of the messages and delivery frequency. There is definitely a correlation. The smaller I make the message sizes, the higher the frequency I can achieve. But, inevitably, I am always able to break it.

So, to more accurately describe what I am looking for is:

To understand what is happening. This will help me identify a possible solution or, at a minimum, establish thresholds for reliable behavior.

Implement a fail-safe mechanism so when the problem occurs, I can handle it and possibly recover from it. Perhaps adding a checksum into the data stream or something like that.

Here is the code that I am running in the client (receiving) applications:

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;
        }
    }
}

解决方案

Without seeing your code, we can only guess. My guess is: Are you considering the case where you read less than the full 4-byte header? You might only read one, two, or three bytes of it. Higher data volumes will cause this to happen more often.

Since TCP is a reliable protocol, this is not due to packet loss. Any lost packets result in one of two things happening:

The missing data is retransmitted and the receiver experiences a short pause, but never sees missing data or data out of order. The socket is closed.

UPDATE

Your IsComplete method returns true after a partial length has been written to the buffer. This causes your receiver code in ProcessData() to discard the length buffer bytes already received, and then gets out of sync.