我们正在Windows Embedded CE 6平台上开发.NET CF 3.5应用程序。我们试图在.NET中实现一个小型(HTTP 1.0)Web服务器,该服务器应该提供WebApp并响应简单的REST请求。通过更改SOMAXCONN来增加Windows CE中的最大积压?
我们的实施遵循此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参数来配置 - 这个参数有一个依赖plattform的最大值。如果积压队列耗尽,则在三次握手期间拒绝新的tcp连接请求(客户端/浏览器获取RST作为对syn的响应)。
现在我们碰到了这个问题,大多数现代浏览器如Firefox,Chrome,Safari等使用最多15个(或更多)的并发连接从服务器加载数据(每个主机的最大并发连接数可以在Firefox中使用about:config - > network.http.max-connections-per-server)进行配置。加载页面时,浏览器根据需要加载的资源数量(例如图像,javascript或css文件)建立15个连接。
.NET CF socket.listen方法(请参阅http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.listen.aspx)允许定义积压编号。
根据我们的理解,我们应该有一个积压超过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? (我们能够改变平台图像 - 利用plattform生成器)。或者我们对这个问题的理解有错误吗?
我们连接,我们目前正在使用的源代码:
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);
}
嗨克里斯,感谢您的快速响应,我已更新我的文章,以提供更多的见解,并显示/验证我们对这个特定事件的理解!根据我的理解,我们已经使用异步套接字处理。 – Chris 2012-04-14 15:44:53
我必须去看看Padarn来源,看看我们使用的模式是什么样子,但我确实知道我们没有调整积压,并且我们没有遇到任何问题请求,甚至来自多个客户端,并且当一个页面使用很多请求时,需要很多请求到服务器来呈现页面。我会尽快看到能否实现,但可能是星期一。 – ctacke 2012-04-14 16:20:58
请你首先回答问题,然后你可以提出建议,一个建议,尤利只是一个评论。 – 2017-07-07 08:30:14