处理来自套接字侦听器的命令时出现延迟



我有一个特殊的套接字侦听器,它在它的线程中工作。它的工作是从更新数据库的外部程序中获取命令。当命令出现在套接字上时,我正在调用一个特殊的方法,该方法从数据库更新我的应用程序缓存。

我有一个问题,就是从外部程序发送命令和在我的应用程序(ASP.NET应用程序)中处理该命令之间的延迟。每天我的应用程序在凌晨4点重新启动,到一天结束时,我会延迟大约1-2个小时。

如何减少延迟?

你可以在下面找到我的监听器的代码。

谢谢。

public delegate void OnECIGetCommand( string command );
public class ECIMain
{
protected Socket socket;
protected string ip;
protected int port;
private static ECIMain INSTANCE = null;
const int receivedDataSize = 250;
protected static byte[] buffer = new byte[ receivedDataSize ];  
protected static StringBuilder sb;                              
protected static DoWorkEventHandler onCommand;              
private ECIMain() 
{
socket = new Socket(AddressFamily.InterNetwork, 
SocketType.Stream, ProtocolType.Tcp);
sb = new StringBuilder();
}
private void StartSocket()
{
sb.Clear();
socket.Listen(1);
socket.BeginAccept(null, receivedDataSize, 
new AsyncCallback(AcceptReceiveDataCallback), socket);
}
private static void AcceptReceiveDataCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
// End the operation and display the received data on the console.
byte[] Buffer;
int bytesTransferred;
Socket handler = listener.EndAccept(out Buffer, 
out bytesTransferred, ar);
HandleBuff(bytesTransferred, Buffer);
// Create the state object for the asynchronous receive. 
handler.BeginReceive(buffer, 0, receivedDataSize, 
SocketFlags.None, new AsyncCallback(ReadCallback), handler);
}
private static void HandleBuff(int size, byte[] buff )
{
if (size > 0)
{
// There  might be more data, so store the data received so far.
sb.Append(Encoding.ASCII.GetString(buff, 0, size));
// Check for end-of-file tag. If it is not there, read more data.
var content = sb.ToString();
int pos = -1;
if ((pos = content.IndexOf("</cmd>")) > -1)
{
// All the data has been read from the 
// client.
pos += 6; 
if( pos < content.Length )
content = content.Remove(pos);

var startPos = content.LastIndexOf("<cmd>");
if( startPos > -1 ) 
{
if (startPos > 0)       
content = content.Remove(0, startPos);
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += onCommand;
worker.RunWorkerAsync(content);
}
sb.Remove(0, pos); 
}
}
}
private static void ReadCallback(IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
Socket handler = (Socket)ar.AsyncState;
SocketError error;
// Read data from the client socket. 
int bytesRead = handler.EndReceive(ar, out error );
if (error == SocketError.Success)
{
if (bytesRead > 0)
{
HandleBuff(bytesRead, buffer);
handler.BeginReceive(buffer, 0, receivedDataSize,
SocketFlags.None, new AsyncCallback(ReadCallback), handler);
}
else 
{
handler.Disconnect(true);
INSTANCE.StartSocket();
}
}
else if (error == SocketError.Shutdown || error == SocketError.ConnectionReset)
{
INSTANCE.StartSocket();   
}
}
public static string InitECI(int port, DoWorkEventHandler commandHandler)
{
if (INSTANCE == null)
{
INSTANCE = new ECIMain();
INSTANCE.port = port;
onCommand += commandHandler;
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList
.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
INSTANCE.ip = ipAddress.ToString();
try
{
INSTANCE.socket.Bind(localEndPoint);
}
catch (System.Net.Sockets.SocketException e)
{
if (e.SocketErrorCode == System.Net.Sockets
.SocketError.AddressAlreadyInUse)
{
//INSTANCE.socket.Bind(localEndPoint);
}
throw e;
}
INSTANCE.StartSocket();
}
return INSTANCE.ip;
}
public static void ShutDownECI()
{
if( INSTANCE.socket.Connected )
INSTANCE.socket.Disconnect(false);
INSTANCE.socket.Close();
}
}

当使用TCP堆栈(发送或接收)时,必须将堆栈视为自己的系统,它是防弹的,工作得很好。。。这些类型的问题大多涉及这样一个事实,即应用层可以轻松地启动任意多的异步操作,但这并不意味着TCP堆栈会更快,尤其是在它不堪重负的情况下。相反,这意味着它将排队并尽可能处理任务。

堆栈不堪重负的症状之一是存在许多通过Netstat命令可视化的半会话状态。任何带有"等待"一词的东西都是半状态的指示器。当一方发布数据包,但另一方没有立即响应时,就会发生这种情况。从那时起,一切都在走下坡路,因为TCP启动并试图通过重新发送相同的数据包来保持会话的活力。将其乘以活动会话的数量,再加上TCP在超时前为每个数据包重试多达10次,您可以看到这是不堪重负的堆栈最不需要的。

您的情况可能是网络流量超过了单个网络适配器的容量。这通常可以通过添加更多的网卡和使用其他方式进行负载平衡来解决。一种方法是他们所说的DNS循环,它是最便宜的。另一种方式是F5设备。

最重要的是,听起来你的网络适配器已经不堪重负了。

在电线的两侧,有几件事需要检查。

  • 当每个会话的gig启动时,所有的套接字都完全关闭了吗
  • 您是否能够运行网络监视器来查看总体负载。。。您通常希望任何单个网络适配器的利用率达到或低于60%
  • 如果你的负载太高,那么你可以和DNS人员讨论使用循环,并在同一服务器中放入另一张卡(它将有不同的地址)
  • 有时,这是由于缺乏对有线发送的数据的压缩。你也可以研究压缩技术
  • 有时交换机坏了,这就提供了MAC到MAC的连接能力
  • 不正确的路由器配置可能允许从不同的接入点重新传输线路
  • 配置不正确的服务器也可能传播过多噪音(完全是垃圾)
  • 无线接入点因其不稳定而臭名昭著——它们也可能是噪音的来源

要找到这类问题的根源还有很多,但希望其中的一些想法能对你有所帮助。

最新更新