C# 为什么服务器在从网络流加载XML时会阻塞?

C# 为什么服务器在从网络流加载XML时会阻塞?,c#,xml,networking,xmldocument,networkstream,C#,Xml,Networking,Xmldocument,Networkstream,我有一个简单的C#客户端和服务器。客户机的目标是向服务器发送一个XML文档,然后服务器应使用不同的XML文档进行响应。当我尝试使用XmlDocument.Load(NetworkStream)接收输入/请求XML时,服务器正在阻塞 服务器: TcpListener t = new TcpListener(IPAddress.Any, 4444); t.Start(); TcpClient c = t.AcceptTcpClient();

我有一个简单的C#客户端和服务器。客户机的目标是向服务器发送一个XML文档,然后服务器应使用不同的XML文档进行响应。当我尝试使用XmlDocument.Load(NetworkStream)接收输入/请求XML时,服务器正在阻塞

服务器:

        TcpListener t = new TcpListener(IPAddress.Any, 4444);
        t.Start();
        TcpClient c = t.AcceptTcpClient();
        NetworkStream s = c.GetStream();
        XmlDocument req = new XmlDocument();
        req.Load(s);

        string respString = "<response><data>17</data></response>";
        XmlDocument resp = new XmlDocument();
        resp.LoadXml(respString);
        resp.Save(s);
TcpListener t=新的TcpListener(IPAddress.Any,4444);
t、 Start();
TcpClient c=t.AcceptTcpClient();
NetworkStream s=c.GetStream();
XmlDocument req=新的XmlDocument();
所需负荷;
字符串respString=“17”;
XmlDocument resp=新的XmlDocument();
resp.LoadXml(respString);
分别保存;
客户:

        TcpClient t = new TcpClient("localhost", 4444);
        NetworkStream s = t.GetStream();

        string reqStr = "<request><parameters><param>7</param><param>15</param></parameters></request>";
        XmlDocument req = new XmlDocument();
        req.LoadXml(reqStr);

        req.Save(s);

        XmlDocument resp = new XmlDocument();
        resp.Load(s);

        Console.WriteLine(resp.OuterXml);
TcpClient t=新的TcpClient(“localhost”,4444);
NetworkStream s=t.GetStream();
字符串reqStr=“715”;
XmlDocument req=新的XmlDocument();
req.LoadXml(reqStr);
请求保存;
XmlDocument resp=新的XmlDocument();
相应荷载;
Console.WriteLine(分别是OuterXml);
在客户机将请求XmlDocument保存到流之后,我尝试在客户机中添加Flush(),但这似乎没有帮助。最初我尝试让服务器将所有输入从客户端读取到MemoryStream,但后来我发现无法向服务器表明所有输入都是在不断开连接的情况下完成的,这意味着客户端无法读取其输入


我可以使用netcat将XML输入从文件发送到服务器,一切正常。无论我是在服务器中使用XmlDocument.Load(NetworkStream),还是将所有输入读取到MemoryStream中,这都是有效的。netcat在这种情况下做了什么,而我没有在我的C#client中做什么,我如何在C#中做?我应该换一种方式吗?

Tcp连接是双向的,您可以关闭其中一半,而另一半仍然打开。在这种情况下,您可以在发送所有数据后关闭客户端到服务器的一半,然后仍然可以通过服务器到客户端的一半接收响应。对于您的示例,您可以这样做:

TcpClient t = new TcpClient("localhost", 4444);
NetworkStream s = t.GetStream();
string reqStr = "<request><parameters><param>7</param><param>15</param></parameters></request>";
XmlDocument req = new XmlDocument();
req.LoadXml(reqStr);
req.Save(s);
// important line here! shutdown "send" half of the socket connection.
t.Client.Shutdown(SocketShutdown.Send);
XmlDocument resp = new XmlDocument();
resp.Load(s);
Console.WriteLine(resp.OuterXml);
TcpClient t=新的TcpClient(“localhost”,4444);
NetworkStream s=t.GetStream();
字符串reqStr=“715”;
XmlDocument req=新的XmlDocument();
req.LoadXml(reqStr);
请求保存;
//这里很重要!关闭“发送”一半的套接字连接。
t、 Client.Shutdown(SocketShutdown.Send);
XmlDocument resp=新的XmlDocument();
相应荷载;
Console.WriteLine(分别是OuterXml);
发送所有数据后,不要忘记在服务器端处理网络流:

TcpListener t = new TcpListener(IPAddress.Loopback, 4444);
t.Start();
TcpClient c = t.AcceptTcpClient();
using (NetworkStream s = c.GetStream()) {
    XmlDocument req = new XmlDocument();
    req.Load(s);                
    Console.WriteLine("Got request: {0}", req.OuterXml);
    string respString = "<response><data>17</data></response>";
    XmlDocument resp = new XmlDocument();
    resp.LoadXml(respString);
    resp.Save(s);
}
TcpListener t=新的TcpListener(IPAddress.Loopback,4444);
t、 Start();
TcpClient c=t.AcceptTcpClient();
使用(networkstreams=c.GetStream()){
XmlDocument req=新的XmlDocument();
所需负荷;
WriteLine(“Got请求:{0}”,req.OuterXml);
字符串respString=“17”;
XmlDocument resp=新的XmlDocument();
resp.LoadXml(respString);
分别保存;
}
事实上,如果整个通信是一个请求接一个响应,那么您可以使用此技术,而不是通过tcp使用自定义协议(请记住使用超时并正确处理您的流和tcp客户端)


否则,请记住,网络流是客户端和服务器之间的一种开放连接—它没有显式的“结束”。在执行XmlDocument.Load时,它将一直读取,直到有可能为止(也就是说,直到读取返回0字节读取),因此它会在您的情况下阻塞。您应该通过tcp定义自己的协议,以便您自己可以定义消息边界。简单的方法是-前4个字节定义以下消息的长度。因此,您先读取前4个字节,然后再读取,直到达到该长度或超时为止。

防火墙如何?阻止流的原因可能很多,就像防火墙或病毒检查器阻止端口号一样。我首先尝试看看是否可以使用IE web浏览器手动下载xml。如果可以,那么这不是防火墙问题。然后,我会使用wireshark或fiddle等嗅探器捕获IE下载,并将结果与c#应用程序进行比较。通常问题是c#应用程序中的http头需要修改以匹配IE结果。这不是防火墙或网络问题-来自同一台机器的netcat可以发送所需的输入。我不知道如何用IE测试这个场景,因为IE不会向我的服务器发送XML请求。另外,Windows防火墙已经关闭。@jdweng这里没有涉及http。@skipopoppy看到更新,我认为它以更完整的方式回答了您的问题。谢谢,@Evk,我认为Client.Shutdown(SocketShutdown.send)也许是我一直错过的。我昨天在Shutdown()中绊倒了,但没有意识到有参数告诉它只关闭一侧。老鼠。当我尝试Client.Shutdown(SocketShutdown.Send)时,它会让我走得更远一些,但当客户端尝试读取服务器正在发送的内容时,它会得到“无法从传输连接读取数据:远程主机强制关闭了现有连接”这听起来好像双方都被关闭了。用我用于测试的服务器代码更新了我的答案(工作正常,没有任何错误)。也许你忘了关闭服务器端(没有处理NetworkStream)或者别的什么。是的-当我在服务器端关闭它而不是让服务器处理它时,我很好。谢谢-你已经解决了我的问题!我知道这是可能的;只是不知道如何明确地结束连接的一端。昨天我因为问了一个不同的问题而被另一个问题打断了;有人告诉我这是不可能的。