0

我有这个非常奇怪的错误。基本上,只要我添加代码行 Connections.Add(handler); 我的程序出了问题。我也收到错误:

System.OutOfMemoryException:引发了“System.OutOfMemoryException”类型的异常。在 System.Threading.ExecutionContext.CreateCopy() 在 System.Net.ContextAwareResult.CaptureOrComplete(ExecutionContext& cachedContext, Boolean returnContext)

发生的情况是,当我添加此代码时,仍然接受连接,但我的日志 Richtextbox 控件上没有记录任何内容。这很奇怪,我不知道发生了什么。但是,在我的接受事件中删除 Connections.Add(handler) 行可以解决所有问题。但是我需要以某种方式跟踪套接字,以便我可以实现 ping 以使它们保持活动状态

这是我的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Concurrent;

namespace SpybotServer
{  
    public partial class Server : Form
    {  

        public void log(String text)
        {
            logs.InvokeEx(a => a.Text += (text +Environment.NewLine));
        }

        public Server()
        {
            InitializeComponent();            
        }

        private void Server_Load(object sender, EventArgs e)
        {            
            Thread serverThread = new Thread(delegate()
                {
                    Listener.StartListening(9001);
                });
            serverThread.Start();
            heartbeat.Start();
        }

        private void Server_FormClosed(object sender, FormClosedEventArgs e)
        {
            Listener.looping = false;
        }

        private void heartbeat_Tick(object sender, EventArgs e)
        {
            Listener.heartbeat();
        }

    }

    public class StateObject
    {
        public Socket workSocket = null;
        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public StringBuilder sb = new StringBuilder();
    }

    public class Listener
    {       
        public static Boolean looping = true;
        private static List<Socket> Connections = new List<Socket>();

        public static void heartbeat()
        {
            Program.MainForm.log("Sending ping...");             
        }

        public static void StartListening(int port)
        {
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 9001);
            Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Program.MainForm.log("Listening on port " + port);

            try
            {
                listener.Bind(localEndPoint);
                listener.Listen(100);

                while (looping)
                {
                    listener.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        listener);
                }
            }
            catch (Exception e)
            {
                Program.MainForm.log(e.ToString());
            }
        }

        public static void AcceptCallback(IAsyncResult ar)
        {
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            StateObject state = new StateObject();
            state.workSocket = handler;
            IPEndPoint ip = handler.RemoteEndPoint as IPEndPoint;                    

            Program.MainForm.log("Accepted connection from " + ip.Address);
            //Connections.Add(handler);

            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
        }

        public static void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;
            StateObject state = (StateObject) ar.AsyncState;
            Socket handler = state.workSocket;

            try
            {
                int bytesRead = handler.EndReceive(ar);

                if (bytesRead > 0)
                {
                    state.sb.Append(Encoding.ASCII.GetString(
                        state.buffer, 0, bytesRead));

                    content = state.sb.ToString();                    

                    /*if (content.IndexOf("!@<EOF_END>@!") > -1)
                    {
                        Program.MainForm.log(content);
                    }
                    else
                    {
                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                            new AsyncCallback(ReadCallback), state);
                    }*/
                }
            }
            catch (Exception e)
            {
                Program.MainForm.log(e.ToString());
            }
        }


        private static void Send(Socket handler, String data)
        {
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            handler.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback(SendCallback), handler);
        }

        private static void SendCallback(IAsyncResult ar)
        {
            Socket handler = (Socket)ar.AsyncState;

            try
            {                
                int bytesSent = handler.EndSend(ar);
                if (bytesSent <= 0)
                {
                    Program.MainForm.log("Socket has been closed.");
                }

            }
            catch (Exception e)
            {
                Program.MainForm.log(e.ToString());
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
        }

    }
}

调用Ex:

using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace SpybotServer
{
    static class ISynchronizeInvokeExtensions
    {
        public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
        {
            if (@this.InvokeRequired)
            {
                @this.Invoke(action, new object[] { @this });
            }
            else
            {
                action(@this);
            }
        }
    }
}
4

2 回答 2

1

由于这个回调:

public static void AcceptCallback(IAsyncResult ar)

在这个循环内:

while (looping)
{
    listener.BeginAccept(
        new AsyncCallback(AcceptCallback),
        listener);
}

我有超过 90% 的把握,您会一遍又一遍地将相同的内容添加SocketConnections列表中,并且只会以惊人的速度增加列表的大小。将添加更改为:

if (Connections.Contains(handler))
{
    Connections.Add(handler);
}
于 2013-04-23T18:28:21.133 回答
0

迈克尔走在正确的轨道上,但没有找到正确的解决方案。

listener.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    listener);

如果你这样称呼它, (不像Accept)不会阻塞并且会发生奇怪的事情。而是让您BeginAccept退出循环并再次调用它,AcceptCallback以便您在接受第一个连接可以接受新连接。

于 2013-04-23T18:44:58.623 回答