2012-04-13 18 views
2

Windows Embedded CE 6プラットフォーム上で.NET CF 3.5アプリケーションを開発しています。私たちは、小さな(HTTP 1.0)Webサーバーを.NETに実装しようとしています。これは、Webアプリケーションを提供し、単純なREST要求に応答する必要があります。SOMAXCONNを変更して、Windows CEの最大バックログを増やしますか?

この実装は、このMSDN記事のパターンに従います。http://msdn.microsoft.com/en-us/library/aa446537.aspx。 BeginAccept、EndAccept、BeginRecieve、EndReceiveと組み合わせて、TCPリスニングソケット、非同期コールバックを使用します。

リスニングポート上の着信接続は、非同期受け入れコールバックによって処理されます。 (http://msdn.microsoft.com/en-us/library/5bb431f9.aspx参照)。 EndAcceptメソッドを呼び出すことによって、この非同期受け入れコールバック内で、リスニングポートに新しいソケットへの接続を渡してポートを解放するように指示し、リスニングポートによって新しい着信接続要求を受け入れることができます。すでに受け入れられた要求は、(非同期コールバックで処理されるため)独自のスレッドで処理されます。

BeginAcceptとEndAcceptの間の時間を最小限に抑えようとしました。 BeginAcceptとEndAcceptを呼び出す間のこの期間中に、着信接続要求はリスニングソケットのバックログキューに配置されるためです。このキューの長さは、いわゆるバックログパラメータによって設定することができます。このパラメータは、プラットフォームに依存する最大値を持ちます。バックログ・キューが使い果たされた場合、新しいtcp接続要求はスリーウェイ・ハンドシェイク中に拒否されます(クライアント/ブラウザーはsynへの応答としてRSTを取得します)。

これで、Firefox、Chrome、Safariなどの最新のブラウザが問題になりました。サーバーからデータをロードするために最大15個(またはそれ以上)の同時接続を使用します(ホストあたりの最大同時接続数は、about:config - > network.http.max-connections-per-serverでFirefoxで設定できます)。ページが読み込まれると、ブラウザは、読み込みが必要なリソースの数に応じて、必要に応じて15個の接続を確立します(画像、javascriptまたはcssファイルなど)。

.NET CF socket.listenメソッド(http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.listen.aspx参照)では、バックログ番号を定義できます。
われわれの理解から、15を超えるバックログが必要です。すべての接続要求がブラウザによって同時にトリガされるため、20人ほどの小さなWebサーバが15同時接続要求でヒットしました。バックログキューのサイズが小さすぎると、TCP接続が中止されます。リスニングソケットがすべて受け入れるまで、すべての着信接続がキューに入るわけではないためです。 FirebugまたはChromeでは、これらのリクエストは「中止」と表示されます。 私たちは、socket.listen(20)を使ってバックログを20に増やし、すべてがうまくいって、最も貪欲なブラウザにも耐えられることを期待しました。

問題は、socket.listen()呼び出しのbacklogパラメータが、SOMAXXCON(この場合、最大5つの接続)にサイレントに設定されていることです。それ以上の数値を設定しても効果はありません。ブラウザが例えばいくつかのソケットが単にバックログキュー5に収まらず、TCP接続がWebサーバーからTCP-RSTを取得し、一部のリソースがWebページにないという事実のために、16の同時ソケット接続が失われました。

Windows Embedded CE 6.0のSOMAXXCONを変更する方法はありますか? (我々は、プラットフォーム画像を変更することができる - プラットフォームビルダーを利用する)。それとも私たちの理解に誤りがありますか? - あなたは間違いなくバックログ要求数を変更することなく、このsceanrioを扱うことができる

public class StateObject 
    { 
     // Client socket. 
     public Socket workSocket = null; 
     // Size of receive buffer. 
     public const int BufferSize = 1024; 
     // Receive buffer. 
     public byte[] buffer = new byte[BufferSize]; 
     // Received data string. 
     public StringBuilder sb = new StringBuilder(); 
    } 

public void StartListening() 
    { 
     logger.Debug("Started Listening at : " + this.listeninghostIp + ":" + this.listeningport); 
     IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(this.listeninghostIp), Convert.ToInt32(this.listeningport)); 
     listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

     listener.Bind(localEP); 
     listener.Listen(10); 
     ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForConnections)); 
    } 

public void CheckForConnections() 
    { 
     try 
     { 
      logger.Debug("listening successfully started! Waiting for incoming connections..."); 
      listener.BeginAccept(new AsyncCallback(acceptCallback), listener); 
      } 
     catch (Exception ex) 
     { 
      logger.Error("Exception Occured while starting Listening : " + ex.Message.ToString()); 
     } 
    } 

private void acceptCallback(IAsyncResult ar) 
    { 
     try 
     { 

      Socket listener = (Socket)ar.AsyncState; 
      listener.BeginAccept(new AsyncCallback(acceptCallback), listener); 
      Socket handler = listener.EndAccept(ar); 
      StateObject state = new StateObject(); 
      state.workSocket = handler; 
      handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
     new AsyncCallback(ReadCallback), state); 

      logger.Debug("listening socket accepted connection..."); 

     } 
     catch (Exception ex) 
     { 
      logger.Error("Error on acceptCallback. Error: " + ex.Message); 
     } 

public void ReadCallback(IAsyncResult ar) 
    { 
     String content = String.Empty; 

     StateObject state = (StateObject)ar.AsyncState; 
     Socket handler = state.workSocket; 
     int bytesRead = handler.EndReceive(ar); 

     if (bytesRead > 0) 
     { 
      state.sb.Append(Encoding.ASCII.GetString(
      state.buffer, 0, bytesRead)); 
     } 
     ClientConnectionFactory.createConnection(ar.AsyncState); 
} 

答えて

-1

私はあなたが間違った道を向かっていると思う:

我々は、現在使用しているソースコードを添付しました。

クライアント要求はポート80で受信されますが、応答はポート80のクライアントに戻されません。つまり、非同期ソケット処理を使用して要求を受信し、解析に渡すことができます後続の要求が前の要求の完全な処理を待っていないことを返信します。私たちはPadarn Webサーバーでこの手法を使用しており、単一のクライアントブラウザからの複数の要求や複数の同時クライアントからの複数の要求を処理するのに問題はありません。

+0

こんにちはクリス、あなたの素早い応答のおかげで、私はいくつかのより多くの洞察力を与え、この特定の問題の私たちの理解を確認するために自分の投稿を更新しました!私の理解からは、すでに非同期ソケット処理を使用しています。 – Chris

+0

パドルンのソースを見て、使用しているパターンがどのようなものかを正確に見る必要がありますが、私たちがバックログを調整していないこと、そして紛失複数のクライアントからの要求であっても、ページが多数のインクルードを使用しているときに、そのページをレンダリングするためにサーバーへの多くの要求が必要な場合。私はすぐにそれに行くことができるかどうかを見ていきますが、それは月曜日でしょう。 – ctacke

+0

あなたは最初に質問に答える必要があります。あなたはアドバイスをすることができます。アドバイスはsoleleyだけがコメントになることができます。 –

関連する問題