从套接字侦听器

时间:2016-06-07 11:42:57

标签: c# asp.net-mvc sockets

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

我遇到了一个问题,那就是从外部程序发送命令和在我的应用程序(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();
    }
}

1 个答案:

答案 0 :(得分:0)

当使用TCP堆栈(发送或接收)时,必须将堆栈看作是它自己的系统,这是防弹并且运行良好......大多数这些类型的问题都涉及到这一事实应用程序层可以轻松地根据需要触发尽可能多的异步操作,但这并不意味着TCP Stack会更快,特别是如果它不堪重负。这意味着它将排队并处理任务,因为它能够。

堆栈不堪重负的一个症状是存在通过Netstat命令可视化的许多半会话状态。任何有&#34; Wait&#34;是一个半州的指标。当一方发布数据包但另一方没有立即响应时会发生这种情况。从那里开始,因为TCP开始并试图通过重新发送相同的数据包来保持会话存活,所以它都处于下坡状态。将此值乘以活动会话数以及TCP在超时之前为每个数据包重试最多10次这一事实,您可以看到这是不堪重负的堆栈需要的最后一件事。

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

最重要的是,听起来您的网络适配器正在被淹没。

这是在电线两侧检查的一些事情。

  • 每次进行演出时,是否所有插座都完全关闭?
  • 您是否能够运行网络监视器来查看总体负载......您通常希望在任何单个网络适配器上使用率为60%或更低。
  • 如果您的负载太高,那么您可以与DNS人员讨论使用循环法,并将另一张卡放入同一台服务器(它将具有不同的地址)
  • 有时,由于在线路上发送的数据没有压缩。您也可以调查压缩技术。
  • 有时交换机会变坏,从而提供MAC-To-MAC连接能力。
  • 不正确的路由器配置允许从不同的接入点重新传输线路。
  • 错误配置的服务器也可以播放太多噪音(总垃圾)
  • 无线接入点因出现片状而臭名昭着,它们也可能成为噪音源。

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