【问题标题】:SocketException An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was fullSocketException 由于系统缺少足够的缓冲区空间或队列已满,无法对套接字执行操作
【发布时间】:2011-12-24 08:01:08
【问题描述】:

这个问题可能出在哪里?

SocketException 由于系统缺少足够的缓冲区空间或队列已满,无法对套接字执行操作

Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 50509);
EndPoint tmpRemote = (EndPoint)(sender);

newsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
newsock.Bind(ipep);

    while (thread_Listen == true && work == true)
        {
            try
            {
                Object state = new Object();
                **>> at this place >>** newsock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref tmpRemote, new AsyncCallback(DoReceiveFrom), state);
                Array.Clear(buffer, 0, buffer.Length);
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

func DoReceiveFrom 的样子

private void DoReceiveFrom(IAsyncResult iar)
{
    try
    {
        Socket recvSock = (Socket)iar.AsyncState;
        EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
        int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP);
        byte[] localMsg = GetAndCleanPacket(buffer);
        string[] packet = Encoding.ASCII.GetString(localMsg).Split(new Char[] { '|' });
        if (packet.Length > 0)
        {
            if (packet[0] == "ms")
            {
                // Connect
                if (packet[1] == "c") MSc(ip[0], packet[9], packet, clientEP);
                else if (packet[1] == "s") MSs(ip[0], packet);
                else if (packet[1] == "d") MDc(ip[0], packet);
            }
            else if (packet[0] == "p") ping(clientEP);
            else if (packet[0] == "sList") serverList(clientEP);
            else if (packet[0] == "bi") brGetInfo(packet, clientEP);
            else if (packet[0] == "error") AddError(packet[1], packet[2]);
        }
    }
    catch (InvalidOperationException)
    {
    }
    catch (SocketException)
    {
    }
    catch (Exception e)
    {
        errors.Add(e.ToString());
    }
}

【问题讨论】:

  • 缓冲区数组的长度是多少?
  • 1024 尝试了 2048,但有相同的异常
  • DoReceiveFrom 长什么样子?

标签: c# queue socketexception


【解决方案1】:

您的 while 循环以非常高的速率调用 BeginReceiveFrom()。在操作系统拔掉插头并拒绝分配更多资源之前,应该不会超过几分之一秒。

您必须以不同的方式执行此操作,仅在您收到某些内容后调用 BeginReceiveFrom。在 DoReceiveFrom() 中。

【讨论】:

    【解决方案2】:

    我所做的是使用包含“IAsyncResult”对象的“StateObject”类。这应该用于 TCP 和 UDP。这是 UDP 的示例。

        // Used for receiver to signal client that data has been received
        // 'readonly' for .Net 4.8
        private readonly ManualResetEvent receiveDone = new ManualResetEvent(false);
    
        /// <summary>
        /// Supports async receive on UDP socket
        /// </summary>
        private class StateObject
        {
            // Client socket.  
            public UdpClient workSocket = null;
            // Receive buffer.  
            public byte[] buffer;
            // Received data string.  
            public StringBuilder sb = new StringBuilder();
            //public int bytesRead;
            // receiver state
            public IAsyncResult result;
    
            public delegate void RecvMethod(IAsyncResult result);
    
            public void BeginReceive(RecvMethod recvMethod, UdpClient udpClient)
            {
                // Set the socket
                workSocket = udpClient;
                // start async receiver
                result = workSocket.BeginReceive(new AsyncCallback(recvMethod), this);
            }
        }
    

    “Receive”方法(由客户端应用调用)检查其状态,并且仅在接收器未发出信号(使用 receiveDone)且 IAsyncResult.Completed 为 false 时触发。

    这是这里的关键:如果接收器仍然处于活动状态,请不要再次触发它,否则您会浪费系统资源。它需要另一个套接字和缓冲内存空间,这会占用您的应用程序,通常是在您尝试与离线设备通信时。

        /// <summary>
        /// Set up async receive handler
        /// </summary>
        /// <returns></returns>
        public void Receive()
        {
            // if receiver running, no packet received - do not restart receiver!
            // did receiver signal done?
            if (receiveDone.WaitOne(0))
            {
                // yes - do not restart receiver!
            }
            // is receiver still running?
            else if (CurrentState.result != null && !CurrentState.result.IsCompleted)
            {
                // yes - do not restart receiver!
            }
            else
            {
                // Begin receiving the data from the remote device.
                CurrentState.BeginReceive(ReceiveCallback, udpClient);
            }
        }
    

    接收回调如下所示:

        /// <summary>
        /// End receive (with blocking) and process received data into buffer
        /// </summary>
        /// <param name="ar">Information about the async operation</param>
        private void ReceiveCallback(IAsyncResult ar)
        {
            // Retrieve the state object and the client socket
            // from the asynchronous state object.
            StateObject st = ar.AsyncState as StateObject;
            UdpClient client = st.workSocket;
    
            try
            {
                st.buffer = client.EndReceive(ar, ref receivePoint);
                // Read data from the remote device.
                receiveDone.Set();
            }
            // Since this is a callback, catch any error
            // ObjectDisposedException has been seen
            catch (ObjectDisposedException)
            { }
            // "An existing connection was forcibly closed by remote host" has been seen
            // see https://stackoverflow.com/questions/38191968/c-sharp-udp-an-existing-connection-was-forcibly-closed-by-the-remote-host for further information
            catch
            {
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2014-12-12
      • 2011-05-23
      • 1970-01-01
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 2013-06-14
      • 2015-12-18
      • 1970-01-01
      相关资源
      最近更新 更多