C#、异步套接字服务器/客户端、StackOverflowException

标签 c# sockets asynchronous stack-overflow

我正在使用 C# 编写异步服务器和客户端。我从 MSDN 中获取示例代码,修改并使其多次发送和接收消息。我尝试将 5 个或更多客户端连接到服务器并且它有效但在第 98 次迭代时每个 client 抛出异常 StackOverflow。谁能解释我为什么会收到此错误?我在 MSDN 中读到我的无限循环问题,但我不明白如何更改我的代码并在没有循环的情况下编写它。

此服务器-客户端应该用于多人赛车游戏,我需要每秒多次发送和接收每个玩家的坐标。如果没有无限循环,我该怎么做?

这是我的代码:

服务器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;


public class Server
{
    Socket main_tcp_Sock;
    private static ManualResetEvent acceptDone = new ManualResetEvent(false);
    private static ManualResetEvent sendDone = new ManualResetEvent(false);
    private static ManualResetEvent recvDone = new ManualResetEvent(false);
    private static ManualResetEvent closeDone = new ManualResetEvent(false);
    //int cl_Count = 0;
    List<StateObject> connection_List = new List<StateObject>();
    private static String response = String.Empty;


    public class StateObject
    {
        public Socket current_Socket = null;
        public byte[] data = new byte[256];
        public string id = string.Empty;
    }
    public Server()
    {
        Server_Start();
    }

    public void Server_Start()
    {

        //Creating socket
        main_tcp_Sock = new Socket(AddressFamily.InterNetwork,
                                  SocketType.Stream,
                                  ProtocolType.Tcp);
        IPEndPoint ipLocal = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2000);
        //Bind socket
        try
        {
            main_tcp_Sock.Bind(ipLocal);
            Console.WriteLine("Server has started successfully!");


            //Start listening
            main_tcp_Sock.Listen(100);
            while (true)
            {

                acceptDone.Reset();
                Console.WriteLine("Waiting for a connection...");

                //AsyncAccept
                main_tcp_Sock.BeginAccept(new AsyncCallback(On_Connect), main_tcp_Sock);
                acceptDone.WaitOne();
                Console.WriteLine("\nPress any button to continue...\n\n");
                Console.ReadKey(true);
            }
        }

        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }

    }

    public void On_Connect(IAsyncResult asyn)
    {

        try
        {

            Socket listener = (Socket)asyn.AsyncState;
            Socket handler = listener.EndAccept(asyn);
            acceptDone.Set();

            StateObject connection = new StateObject();
            connection.current_Socket = handler;

            if (!connection_List.Contains(connection))
            {
                lock (connection_List)
                {
                    connection_List.Add(connection);
                    connection.id = "00" + connection_List.Count.ToString() + " ";
                 }
            }
            recvDone.Reset();
            Receive(connection.current_Socket);
            recvDone.WaitOne();

            sendDone.Reset();
            Send(connection.current_Socket, response);
            sendDone.WaitOne();

            closeDone.Reset();
            Socket_Close(connection.current_Socket);
            closeDone.WaitOne();
        }

        catch (Exception e)
        {
            Console.WriteLine("On_Connect Error: {0}", e.ToString());
            Console.ReadKey(true);
        }
    }

    public void Receive(Socket handler)
        {
        try{
            StateObject connection = new StateObject();
            connection.current_Socket = handler;
            connection.current_Socket.BeginReceive(connection.data, 0, connection.data.Length, 0,
                new AsyncCallback(On_Receive), connection);
        }
        catch (Exception e){
        Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }

    }
    public void On_Receive(IAsyncResult asyn)
    {
        string content = "";
        string temp = "";
        StateObject connection = (StateObject)asyn.AsyncState;
        Socket handler = connection.current_Socket;
        int size = handler.EndReceive(asyn);


        Console.WriteLine("ConnID from receive: " + connection.id);
        if (size > 0)
        {
            temp += Encoding.ASCII.GetString(connection.data);
        }
        if (temp.IndexOf("<EOF>") > -1)
        {

            content += temp.Substring(0, temp.IndexOf("\0"));
            Console.WriteLine("Read {0} bytes from socket. \nMessage: {1}", content.Length, content);

            lock (connection_List)
            {
                foreach (StateObject conn in connection_List)
                {
                    if (conn != connection)
                    {
                    content.Insert(0, connection.id);
                    response = content;
                   }

                }
            }
            recvDone.Set();
        }
        else
        {
            handler.BeginReceive(connection.data, 0, connection.data.Length, 0, new AsyncCallback(On_Receive), connection);
        }

    }

    public void Send(Socket handler, String message)
    {
        byte[] data = Encoding.ASCII.GetBytes(message);
        handler.BeginSend(data, 0, data.Length, 0, new AsyncCallback(On_Send), handler);

    }

    public void On_Send(IAsyncResult result)
    {
        try
        {
            StateObject state = new StateObject();
            Socket handler = (Socket)result.AsyncState;
            state.current_Socket = handler;
            int size = state.current_Socket.EndSend(result);
            if (size > 0)
            {
                sendDone.Set();
            }

            else state.current_Socket.BeginSend(state.data, 0, state.data.Length, SocketFlags.None,
                new AsyncCallback(On_Send), state);
            Console.WriteLine("Bytes sent to client: {0}", size);

            sendDone.Set();
        }

        catch (Exception e)
        {
            Console.WriteLine("On_Send e, error: " + e.ToString());
             Console.ReadKey(true);
        }
    }
    public void Socket_Close(Socket sock)
    {
        sock.LingerState = new LingerOption(true, 3);

        sock.Shutdown(SocketShutdown.Both);
        sock.Close();
        closeDone.Set();
    }

}

和客户:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

// State object for receiving data from remote device.
public class StateObject
{
    // Client socket.
    public Socket workSocket = null;
    // Size of receive buffer.
    public const int BufferSize = 256;
    // Receive buffer.
    public byte[] buffer = new byte[BufferSize];
    // Received data string.
    public StringBuilder sb = new StringBuilder();
}

public class AsynchronousClient
{
    public static int count = 0;

    // The port number for the remote device.
    private const int port = 2000;
    // ManualResetEvent instances signal completion.
    private static ManualResetEvent connectDone = new ManualResetEvent(false);
    private static ManualResetEvent sendDone = new ManualResetEvent(false);
    private static ManualResetEvent receiveDone = new ManualResetEvent(false);
    private static ManualResetEvent closeDone = new ManualResetEvent(false);
    // The response from the remote device.
    private static String response = String.Empty;

    private static void StartClient()
    {
        // Connect to a remote device.

        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
        // Create a TCP/IP socket.
        Socket client = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
        Start(client, remoteEP);

    }


    public static void Start(Socket client, EndPoint remoteEP)
    {
        try
        {
            while (true)
            {
                /*if (count >= 30)
                {

                    Thread.Sleep(1000);
                    if (count >= 100)
                    {
                        count = 0;
                        Thread.Sleep(1500);
                    }
                }*/

                Console.WriteLine(count);
                connectDone.Reset();
                client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
                connectDone.WaitOne();


                // Send test data to the remote device.
                sendDone.Reset();
                Send(client, "Some text and <EOF>");
                sendDone.WaitOne();

                // Receive the response from the remote device.
                receiveDone.Reset();
                Receive(client);
                receiveDone.WaitOne();

                // Write the response to the console.
                Console.WriteLine("Response received : {0}", response);

                // Release the socket.
                closeDone.Reset();
                Socket_Close(client);
                closeDone.WaitOne();

                ++count;
            }

        }
        catch (ObjectDisposedException)
        {
            Socket sock = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);

            Start(sock, remote);

        }
        catch (SocketException)
        {
            Socket sock = new Socket(AddressFamily.InterNetwork,
                       SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);

            Start(sock, remote);

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }
    }

    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete the connection.
            client.EndConnect(ar);

            Console.WriteLine("Socket connected to {0}",
                client.RemoteEndPoint.ToString());

            // Signal that the connection has been made.
            connectDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }
    }

    private static void Receive(Socket client)
    {
        try
        {
            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = client;

            // Begin receiving the data from the remote device.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);

        }
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the state object and the client socket 
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            // Read data from the remote device.
            int bytesRead = client.EndReceive(ar);

            if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                // Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // All the data has arrived; put it in response.
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }
                // Signal that all bytes have been received.
                receiveDone.Set();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);

        }
    }

    private static void Send(Socket client, String data)
    {
        try
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.
            client.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback(SendCallback), client);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }
    }

    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device.
            int bytesSent = client.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to server.", bytesSent);

            // Signal that all bytes have been sent.
            sendDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }
    }

    public static void Socket_Close(Socket sock)
    {
        try
        {
            sock.LingerState = new LingerOption(true, 3);
            sock.Shutdown(SocketShutdown.Both);
            sock.Close();
            closeDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.ReadKey(true);
        }
    }

    public static int Main(String[] args)
    {

        StartClient();
        return 0;
    }
}

我是 C# 新手。请帮助某人。

最佳答案

while (true) 永远不会停止......你必须做一些像 while (foo) { if (somecondition) foo=false }

编辑:也许本教程会有所帮助

http://www.codeguru.com/csharp/csharp/cs_date_time/timeroutines/article.php/c7763

片段:

using System;
using System.Timers;

class myApp
{
  public static void Main()
  {
    Timer myTimer = new Timer();
    myTimer.Elapsed += new ElapsedEventHandler( DisplayTimeEvent );
    myTimer.Interval = 1000;
    myTimer.Start();

    while ( Console.Read() != 'q' )
    {
        ;    // do nothing...
    }
  }

  public static void DisplayTimeEvent( object source, ElapsedEventArgs e )
  {
      Console.Write("\r{0}", DateTime.Now);
  }
}

关于C#、异步套接字服务器/客户端、StackOverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2302763/

相关文章:

c# - 在异步 Azure 函数中捕获异常的位置

c# - 如何将以下嵌套 SQL 实现为 Lambda 语句

c++ - 如何创建 802.11 帧?

c# - 真的很长的消息在套接字接收时被切断

javascript - Promise Chaining 和 .then/.catch 语句

c# - 等待与 task.Result 相同的已完成任务?

c# - 在 C# ASP.NET 中使用 LINQ 返回接下来的 5 行?

c# - MVP,类应该在哪里创建?

c# - CUDA 驱动程序 API 与 CUDA 运行时

java - 强制 Java Android Socket 立即发送数据