我们正在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侦听套接字,async-callbacks与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中配置为:config - > network.http.max-connections-per-server) 。加载页面时,浏览器会在需要时建立连接,具体取决于需要加载的资源数量(例如图像,javascript或css文件)。
.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 - 并且网页上缺少一些资源。 / p>
有没有办法在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);
}
答案 0 :(得分:-1)
我认为你走错了路 - 你绝对可以在不改变积压请求号的情况下处理这个问题。
客户端请求进入端口80,但响应不会返回到端口80上的客户端。这意味着您可以使用异步套接字处理来接收请求,然后将其传递给解析和以这种方式回复后续请求不等待以前请求的完整处理。我们在Padarn Web服务器中使用这种技术,处理来自单个客户端浏览器的多个请求甚至来自多个同时客户端的多个请求都没有问题。