2010-05-08 91 views
3

我正在C#中的Web服務器上工作,我讓它在異步套接字調用上運行。奇怪的是,由於某種原因,當你開始加載頁面時,第三個請求就是瀏覽器不能連接的地方。它只是不停地說「連接...」,並不會停止。如果我停下來。然後刷新,它會再次加載,但如果我在此之後嘗試另一次,它會執行不再加載的事情。它在那個週期中繼續。我不確定是什麼讓它做到這一點。奇怪的表現與C#異步服務器套接字

該代碼是從一些例子和一些舊的代碼我一起黑客入侵。任何雜項提示也會有所幫助。

我的繼承人小監聽器類來處理一切

pastied here認爲它可能是更容易閱讀這種方式)

using System; 
using System.Collections.Generic; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Threading; 
using irek.Request; 
using irek.Configuration; 
namespace irek.Server 
{ 
    public class Listener 
    { 
     private int port; 
     private Socket server; 
     private Byte[] data = new Byte[2048]; 
     static ManualResetEvent allDone = new ManualResetEvent(false); 
     public Config config; 

     public Listener(Config cfg) 
     { 
      port = int.Parse(cfg.Get("port")); 
      config = cfg; 
      ServicePointManager.DefaultConnectionLimit = 20; 
     } 

     public void Run() 
     { 
      server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      IPEndPoint iep = new IPEndPoint(IPAddress.Any, port); 
      server.Bind(iep); 

      Console.WriteLine("Server Initialized."); 
      server.Listen(5); 
      Console.WriteLine("Listening..."); 
      while (true) 
      { 
       allDone.Reset(); 
       server.BeginAccept(new AsyncCallback(AcceptCon), server); 
       allDone.WaitOne(); 
      } 

     } 

     private void AcceptCon(IAsyncResult iar) 
     { 
      allDone.Set(); 
      Socket s = (Socket)iar.AsyncState; 
      Socket s2 = s.EndAccept(iar); 
      SocketStateObject state = new SocketStateObject(); 
      state.workSocket = s2; 
      s2.BeginReceive(state.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(Read), state); 
     } 

     private void Read(IAsyncResult iar) 
     { 
      try 
      { 
       SocketStateObject state = (SocketStateObject)iar.AsyncState; 
       Socket s = state.workSocket; 

       int read = s.EndReceive(iar); 

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

        SocketStateObject nextState = new SocketStateObject(); 
        nextState.workSocket = s; 
        s.BeginReceive(state.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(Read), nextState); 
       } 
       if (state.sb.Length > 1) 
       { 
        string requestString = state.sb.ToString(); 
        // HANDLE REQUEST HERE 
        byte[] answer = RequestHandler.Handle(requestString, ref config); 
        // Temporary response 
        /* 
        string resp = "<h1>It Works!</h1>"; 
        string head = "HTTP/1.1 200 OK\r\nContent-Type: text/html;\r\nServer: irek\r\nContent-Length:"+resp.Length+"\r\n\r\n"; 
        byte[] answer = Encoding.ASCII.GetBytes(head+resp); 
        // end temp. 
        */ 
        state.workSocket.BeginSend(answer, 0, answer.Length, SocketFlags.None, new AsyncCallback(Send), s); 
       } 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
       Console.WriteLine(e.StackTrace); 
       return; 
      } 
     } 

     private void Send(IAsyncResult iar) 
     { 
      try 
      { 
       SocketStateObject state = (SocketStateObject)iar.AsyncState; 
       int sent = state.workSocket.EndSend(iar); 
       state.workSocket.Shutdown(SocketShutdown.Both); 
       state.workSocket.Close(); 
      } 
      catch (Exception) 
      { 

      } 
      return; 
     } 
    } 
} 

而且我SocketStateObject:

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

**編輯**

我已經用s更新了代碼來自克里斯泰勒的建議。

+0

檢查我的其他更新響應。我注意到你在BeginSend/Send對中也有一個對象類型不匹配。 – 2010-05-08 09:43:19

回答

1

就趕緊看代碼,我懷疑你可能會停止enquing您AsyncReads因爲s.Available將返回0,我指的下面的代碼

if (read > 0) 
{ 
    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, read)); 
    if (s.Available > 0) 
    { 
     s.BeginReceive(state.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(Read), state); 
     return; 
    } 
} 

爲了確認,上述更改爲以下

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

    SocketStateObject nextState = new SocketStateObject(); 
    nextState.workSocket = s; 
    s.BeginReceive(state.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(Read), nextState); 
} 

這不是代碼的完整的修正,但它會確認這是否是問題。你需要確保你正確地關閉您的插座等

更新 我也注意到,您在調用BeginSend狀態發送插座英寸

state.workSocket.BeginSend(answer, 0, answer.Length, SocketFlags.None, new AsyncCallback(Send), state.workSocket); 

然而,你的回調Send被鑄造AsyncStateSocketStateObject

SocketStateObject state = (SocketStateObject)iar.AsyncState; 

這將提高InvalidCastExceptions你是剛剛加入空catch隱藏。我確信其他人會同意,這是非常不好的做法,它有空的捕獲它隱藏了很多信息,你可以用它來調試你的問題。

+0

不,不幸的是,它沒有改變。所以我不認爲這也是我的問題。但是,這可能會阻止其他錯誤:P – 2010-05-08 08:58:01

+0

@ The.Anti.9,這很奇怪。我剛剛複製了您的原始代碼,可能會複製您的問題。然後,我添加了我所建議的改變,並從那時起將問題消除。也許你可以發佈更新的代碼? – 2010-05-08 09:35:52

+0

好的我更新了它。我只是複製並粘貼了放在我頭頂的代碼,所以我認爲我沒有犯任何錯誤。儘管我可以。我一直在研究應用程序的其他部分,所以現在我認爲我們需要'返回'原因,如果不是這樣,它會嘗試解析一個空請求。並引發異常。 – 2010-05-08 09:44:05

1

完全隨機猜測:

http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit.aspx

通過的ServicePoint 對象允許的併發 連接的最大數目。默認值是2

+0

這是一個很好的想法,但不是。我正在嘗試的連接不是併發的。他們一個接一個地分開。儘管我確實認爲出於某種原因,這些關係並沒有關閉,所以這是有道理的。但唉,不是這樣:/ – 2010-05-08 06:58:32

0

您還應該注意,代碼中存在爭用條件。在run(),你再次調用BeginAccept之前等待allDone:但在你的AcceptConn回調

while (true) 
{ 
    allDone.Reset(); 
    server.BeginAccept(new AsyncCallback(AcceptCon), server); 
    allDone.WaitOne(); // <------ 
} 

這是罰款,該事件被設定在方法的頂部:

private void AcceptCon(IAsyncResult iar) 
{ 
    allDone.Set(); // <------ 

    Socket s = (Socket)iar.AsyncState; 
    Socket s2 = s.EndAccept(iar); 
    SocketStateObject state = new SocketStateObject(); 
    state.workSocket = s2; 
    s2.BeginReceive(state.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, 
     new AsyncCallback(Read), state); 
} 

回調將由池中的隨機線程執行,但allDone將在實際完成之前設置。在AcceptCon的工作實際完成之前,完全有可能讓Run()循環在第一個線程中再次運行。這會導致你很大的問題。

您應該設置allDone你執行初始化後(和你訪問的任何非線程安全類成員尤其是後),就像這樣:

private void AcceptCon(IAsyncResult iar) 
{ 

    Socket s = (Socket)iar.AsyncState; 
    Socket s2 = s.EndAccept(iar); 
    SocketStateObject state = new SocketStateObject(); 
    state.workSocket = s2; 

    allDone.Set(); // <------ 

    s2.BeginReceive(state.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, 
     new AsyncCallback(Read), state); 

}