我有一个服务器软件,它有一个监听套接字,然后跨越多个套接字(10 -30),然后我流数据到这些套接字。
如果我启动我的应用程序,它在我的8 vCPU虚拟机上使用了大约2-3%的cpu使用率。一段时间后,通常是1-2周,应用程序突然开始使用60-70%的cpu使用率,线程计数似乎保持稳定,不会增加。
我在我的代码上运行了我的C#分析器,它归结到以下代码行System.net.Socket.beginReceive()。
我正在使用.net async sockets。下面是我的ReceiveCallBack我怀疑我不是在处理bytesRead不是>0的情况。我应该如何修改下面的函数来正确处理这种情况?
public static void ReadCallback(IAsyncResult ar)
{
SocketState tmpRef = null;
try
{
if (ar != null)
{
tmpRef = (SocketState)ar.AsyncState;
if (tmpRef != null)
{
// Read data from the client socket.
int bytesRead = tmpRef.WorkSocket.Client.EndReceive(ar);
//Start Reading Again
tmpRef.BeginReading(tmpRef._receievCallbackAction);
if (bytesRead > 0)
{
// Check if we have a complete message yet
for (var i = 0; i < bytesRead; i++)
{
if (tmpRef._receiveBuffer[i] == 160)
{
var tmpBuffer = new byte[i];
Array.Copy(tmpRef._receiveBuffer, tmpBuffer, i);
//Execute callback
tmpRef._receievCallbackAction(tmpBuffer);
break;
}
}
}
}
}
}
catch (Exception e)
{
if (tmpRef != null)
{
//Call callback with null value to indicate a failier
tmpRef._receievCallbackAction(null);
}
}
}完整代码:(对不起,我不想弄脏这篇文章) https://www.dropbox.com/s/yqjtz0r3ppgd11f/SocketState.cs?dl=0
发布于 2017-05-03 03:58:07
问题是,如果你没有足够的字节,但你的代码一直在旋转,等待下一个字节出现。
您需要做的是创建一个在调用之间存活的messageBuffer,并对其进行写入,直到获得所需的所有数据。此外,根据代码的外观,您有机会在复制所有数据之前覆盖tmpRef._receiveBuffer,如果您共享一个缓冲区,则需要在复制之后启动BeginReading。
public class SocketState
{
private readonly List<byte> _messageBuffer = new List<byte>(BufferSize);
//...
/// <summary>
/// Async Receive Callback
/// </summary>
/// <param name="ar"></param>
public static void ReadCallback(IAsyncResult ar)
{
SocketState tmpRef = null;
try
{
if (ar != null)
{
tmpRef = (SocketState)ar.AsyncState;
if (tmpRef != null)
{
// Read data from the client socket.
int bytesRead = tmpRef.WorkSocket.Client.EndReceive(ar);
if (bytesRead > 0)
{
//Loop over the bytes we received this read
for (var i = 0; i < bytesRead; i++)
{
//Copy the bytes from the receive buffer to the message buffer.
tmpRef._messageBuffer.Add(tmpRef._receiveBuffer[i]);
// Check if we have a complete message yet
if (tmpRef._receiveBuffer[i] == 160)
{
//Copy the bytes to a tmpBuffer to be passed on to the callback.
var tmpBuffer = tmpRef._messageBuffer.ToArray();
//Execute callback
tmpRef._receievCallbackAction(tmpBuffer);
//reset the message buffer and keep reading the current bytes read
tmpRef._messageBuffer.Clear();
}
}
//Start Reading Again
tmpRef.BeginReading(tmpRef._receievCallbackAction);
}
}
}
}
catch (Exception e)
{
if (tmpRef != null)
{
//Call callback with null value to indicate a failier
tmpRef._receievCallbackAction(null);
}
}
}
//...发布于 2017-05-03 04:06:46
您解释说问题发生在1-2周后,这在当时是很少见的。我建议您通过改进readcallback中的异常处理来引导您的研究方向。
在此异常处理中,您将使用null调用callbackAction。
也许你应该考虑回答以下问题:
当使用null tmpRef._receievCallbackAction(null);
其他一些缺点: begin接收使用this作为状态对象。WorkSocket.Client.BeginReceive(_receiveBuffer, 0, BufferSize, 0, ReadCallback, this);
因此,这意味着读回调的线程安全性不能完全得到保证,因为在您还没有处理_receiveBuffer时,就会发生对BeginReading的调用。
https://stackoverflow.com/questions/43745620
复制相似问题