2

我们正在 Windows Embedded CE 6 平台上开发 .NET CF 3.5 应用程序。我们正在尝试在 .NET 中实现一个小型 (HTTP 1.0) Web 服务器,它应该提供一个 WebApp 并响应简单的 REST 请求。

我们的实现遵循这篇 MSDN 文章中显示的模式:http: //msdn.microsoft.com/en-us/library/aa446537.aspx。我们使用 TCP 监听套接字、异步回调和 BeginAccept、EndAccept、BeginRecieve 和 EndReceive。

侦听端口上的传入连接由异步接受回调处理。(参见http://msdn.microsoft.com/en-us/library/5bb431f9.aspx)。通过调用 EndAccept 方法,在这个异步接受回调中,我们告诉监听端口将连接交给一个新的套接字并释放该端口,以便监听端口可以接受新的传入连接请求。已经接受的请求在一个自己的线程中处理(因为它是在异步回调中处理的)。

我们已经尝试过最小化 BeginAccept 和 EndAccept 之间的时间。因为,在调用 BeginAccept 和 EndAccept 之间的这段时间里,传入的连接请求被放置在侦听套接字的积压队列中。这个队列的长度可以通过所谓的 backlog 参数来配置——这个参数有一个依赖于平台的最大值。如果积压队列已用尽,新的 tcp 连接请求将在三次握手期间被拒绝(客户端/浏览器获取 RST 作为对其 syn 的响应)。

现在我们遇到了一个问题,大多数现代浏览器,如 Firefox、Chrome、Safari,例如使用多达 15 个(或更多)并发连接从服务器加载数据(每个主机的最大并发连接数可以在 Firefox 中配置about:config -> network.http.max-connections-per-server)。当一个页面被加载时,浏览器在需要时建立 15 个连接,这取决于需要加载的资源的数量(例如图像、javascript 或 css 文件)。

.NET CF socket.listen 方法(参见http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.listen.aspx)允许定义积压编号。
根据我们的理解,我们的 backlog 应该大于 15,例如 20 左右,因为所有连接请求都是由浏览器同时触发的,所以我们的小型网络服务器同时受到 15 个连接请求的打击。太小的积压队列大小会导致 TCP 连接中止,因为在侦听套接字可以接受所有传入连接之前,并非所有传入连接都可以排队。在 Firebug 或 Chrome 中,这些请求显示为“已中止”。因此,我们通过 socket.listen(20) 将我们的积压工作增加到 20,并希望一切都会好起来,甚至可以承受最贪婪的浏览器。

问题是,socket.listen() 调用中的 backlog 参数被静默设置为 SOMAXXCON(在我们的例子中最多 5 个连接)。将数字设置得更高则没有效果。当浏览器建立例如 16 个并发套接字连接时,有些会丢失,因为某些套接字根本不适合 5 的积压队列,并且 TCP 连接从网络服务器获得 TCP-RST - 并且缺少一些资源在网页上。

有什么方法可以更改 Windows Embedded CE 6.0 中的 SOMAXXCON?(我们能够更改平台图像 - 使用平台构建器)。还是我们对这件事的理解有误?

我们附上了我们目前正在使用的源代码:

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);
 }
4

1 回答 1

-1

我认为您走错了路-您绝对可以在不更改积压请求编号的情况下处理此场景。

客户端请求进入端口 80,但响应不会返回到端口 80 上的客户端。这意味着您可以使用异步套接字处理来接收请求,然后将其传递给解析并以这种方式回复后续请求不会等待对先前请求的完整处理。我们在我们的 Padarn Web 服务器中使用了这种技术,并且在处理来自单个客户端浏览器的多个请求甚至来自多个同时客户端的多个请求时都没有问题。

于 2012-04-13T15:43:45.003 回答