我需要一些帮助,找出如何解决我正在使用.NET套接字通过TCP进行高容量数据馈送的问题.
简而言之,当客户端应用程序启动时,它将连接到服务器上的特定端口.连接后,服务器开始向客户端发送实时数据,以类似自动收报机的方式显示信息.服务器支持多个客户端工作站,因此数据将通过多个端口(多个套接字)发送.
一切都已实施,并且通过慢速进给和低音量工作.我正在对系统进行压力测试,以确保其可靠性和可扩展性.当我增加频率时,服务器运行完美.但是,我看到客户端上看起来丢失的数据包.这发生在随机时间.
当前,广播的每个消息的前面都有一个4字节的值,用于标识该消息的长度.当我们在客户端接收数据时,我们将数据附加到缓冲区(Stream),直到我们收到该字节数.任何其他字节都被视为下一条消息的开头.同样,这很有效,直到我调高频率.
在我的测试中,我发送一个大约225字节的数据包,然后发送一个大约310kB的数据包和另一个约40kb的数据包.每隔1秒发送一条消息,大约有12个客户端正在运行.将频率增加到1/2秒,我最终看到一个客户端的显示冻结.持续1/4秒,我可以在几秒钟内用少至4个客户端重现问题.
查看我的代码(我可以提供,如果需要),我看到所有客户端都在接收数据,但不知何故信息"不同步",预期长度值很大(在1亿范围内) .因此,我们只是继续阅读数据,从不认识到消息的结束.
我要么需要更好的方法,要么确保获得我期望的数据并且不丢失数据包.你能帮我吗?
UPDATE
我做了大量额外的测试,改变了消息的大小和交付频率.肯定存在相关性.我制作消息大小越小,我可以实现的频率越高.但是,不可避免地,我总能打破它.
因此,更准确地描述我正在寻找的是:
要了解发生了什么.这将帮助我确定可能的解决方案,或者至少为可靠行为建立阈值.
实现故障安全机制,以便在问题发生时,我可以处理它并可能从中恢复.也许在数据流中添加校验和或类似的东西.
这是我在客户端(接收)应用程序中运行的代码:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
没有看到你的代码,我们只能猜测.我的猜测是:您是否正在考虑读取少于完整的4字节标题的情况?您可能只读取其中的一个,两个或三个字节.更高的数据量将导致更频繁地发生这种情况.
由于TCP是可靠的协议,因此不是由于丢包造成的.任何丢失的数据包都会导致以下两种情况之一:
UPDATE
在将部分长度写入缓冲区后,您的IsComplete方法将返回true.这会导致您的接收器代码ProcessData()丢弃已经收到的长度缓冲区字节,然后失去同步.