我需要一些帮助找出如何解决问题,我有一个大容量的数据馈送使用.NET插座目睹了TCP。
在简单地说,客户端应用程序启动时,它连接到服务器上的特定端口。一旦连接,服务器开始发送实时数据,这些数据显示在一个代码状的UI的信息的客户端。该服务器支持多个客户端工作站,因此数据将通过多个端口(多接口)发送。
一切都实现,并与一个缓慢的饲料和小批量伟大的工作。我压力测试制度,确保resiliance和可扩展性。当我提高频率,服务器完美运行。但是,我看到什么出现在客户端上丢失的数据包。这发生在随机时间
目前,每个消息被广播是pfaced具有一个4字节的值,它标识该消息的长度$ P $。由于我们在客户端接收数据,将数据追加到缓冲区(流),直到我们收到的字节数。任何额外的字节被认为是下一个信息的开始。同样,这个伟大工程,直到我打开了的频率。
在我的测试,我送一包约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.