2010-02-20 152 views
2

我正在写一个异步服务器和客户端与C#。我从MSDN获取了示例代码,并进行了修改,并使其多次发送和接收消息。我想5个多的客户连接到服务器,它的工作,但在第98次迭代每个客户抛出异常的StackOverflow。有人可以解释我为什么会出现这个错误吗?我已经阅读MSDN,我的问题在无限循环,但我不明白我该如何更改我的代码,并写入它没有循环。C#,异步套接字服务器/客户端,StackOverflowException

此服务器的客户端应在多人赛车游戏中使用,我需要每秒每个球员的发送和接收的坐标几次。我怎样才能做到没有无限循环?

这里是我的代码:

SERVER:

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#中新。请帮助别人。

+1

而不是在while循环中监听,您也可以使用计时器。 – Adeel 2010-02-20 16:16:31

+0

感谢您的回复,我会在C#中阅读关于计时器的内容,但是您能否解释我有什么不同?为什么循环带来了Stackoverflow,但定时器不? – 2010-02-20 17:17:45

回答

1

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); 
    } 
} 
+0

是的,我知道。当玩家退出游戏时,这个循环将停止,但它在玩游戏时应该起作用,因为它应该发送他自己的坐标并且每秒接收几次其他玩家的坐标。这是不可能的循环?计时器是否更好?为什么?我只是想了解它。谢谢。 – 2010-02-20 17:32:53

+0

是的......一个'while'循环会阻塞线程(直到它退出时什么都不会发生)......你应该设置一个计时器来检查每N毫秒......我可以提供一些ActionScript等效代码(不是C#家伙) – mga 2010-02-20 17:48:41

+0

我想用计时器重写我的代码,但它不起作用。我会尝试更多。谢谢。 – 2010-02-20 20:44:43

1

堆栈是一个后进先出队列。在进行函数调用时,需要保存与所在函数(例如局部变量)相关的状态,以便程序可以处理被调用的函数。当被调用函数返回时,调用函数的状态必须被恢复,所以它从堆栈中被检索。在普通程序中,随着您调用越来越深的嵌套函数,堆栈会不断增长,但随着它们的返回而再次缩小。

当然,堆栈并不是无限的,实际上通常会分配一个固定的内存量,所以如果你有一个嵌套函数调用级别不断增长的程序,堆栈最终会满载,而你会收到堆栈溢出异常。

证明这一点最简单的方法是编写一个函数总是递归调用自己。下面将始终创建一个堆栈溢出:

private void blowTheStack(){ 
    blowTheStack(); 
} 

当然,我们也可以编写递归程序没有这个问题:

private void doSomethingUseful(){ 
    if (!terminatingConditionReached()){ 
    doSomethingUseful(); 
    } 
} 

,这是一个非常强大的技术。编写这样的代码的技巧是让你的终止条件正确!

当这一切发生在一个功能,逻辑是很容易看到,但是,你也可以有类似的逻辑,其中一个函数调用另一个,它调用另一个,它调用第一个函数。

当你和事件处理代码的工作,还有更糟糕的,因为函数调用并不像函数调用了。假设一个函数触发一个触发事件处理程序的条件,并且事件处理程序触发一些调用第一个函数的代码,您也可以使用循环函数调用,并且如果终止条件不正确,则会发生堆栈溢出。

无论如何 - 我只是想+1这个问题,因为它是关于堆栈溢出!