套接字流不包含完整的响应

时间:2014-07-29 08:31:55

标签: c# xml sockets stream

我的c#应用程序中有一些套接字通信。客户端向服务器发送请求(XML字符串),服务器以另一个XML字符串响应。

以下是客户端上运行的代码:

using (TcpClient client = new TcpClient(socket.HostName, socket.Port))
{
    client.SendBufferSize = int.MaxValue;
    client.ReceiveBufferSize = int.MaxValue;
    Stream stream = client.GetStream();

    StreamReader sr = new StreamReader(stream);
    StreamWriter sw = new StreamWriter(stream);
    sw.AutoFlush = true;

    sw.WriteLine(requests.ToXML());

    List<string> xmlStrings = new List<string>();
    while (sr.Peek() > -1)
        xmlStrings.Add(sr.ReadLine());
    string xmlStr = string.Join("\r\n", xmlStrings.ToArray());

    ProcessXMLResponse(xmlStr);

    stream.Close();
    client.Close();
}

这在服务器机器上运行:

using (Stream stream = new NetworkStream(socket))
using (StreamReader sr = new StreamReader(stream))
using (StreamWriter sw = new StreamWriter(stream))
{
    sw.AutoFlush = true;

    List<string> xmlStrings = new List<string>();
        while (sr.Peek() > -1)
    xmlStrings.Add(sr.ReadLine());
    string xmlStr = string.Join("\r\n", xmlStrings.ToArray());
    XmlDocument xml = new XmlDocument();
    xml.LoadXml(xmlStr);

    string responseXML = ProcessXMLRequest(xml);

    sw.WriteLine(response);
    socket.Shutdown(SocketShutdown.Both);
    stream.Close();
}

这段代码似乎大部分时间都有效,但有时候(也许当XML响应很大?)时,客户端似乎只接收XML回复的第一部分。即使数据尚未全部收到,sr.Peek()调用也会返回-1。

知道问题可能是什么?

2 个答案:

答案 0 :(得分:1)

如果您尝试使用

,该怎么办?
sr.ReadToEnd()

而不是

sr.ReadLine()

在双方?

另外,作为建议,您应该投入更多精力来有效地处理资源:

using (TcpClient client = new TcpClient(socket.HostName, socket.Port))
{
    client.SendBufferSize = int.MaxValue;
    client.ReceiveBufferSize = int.MaxValue;

    Stream stream = client.GetStream();
    //generally, you should avoid calling Dispose() on an object multiple times

    //don't put this in a using block as that implicitly calls Dispose() which internally calls Dispose on the stream as well
    StreamReader sr = new StreamReader(stream);

    //don't put this in a using block as that implicitly calls Dispose() which internally calls Dispose on the stream as well
    StreamWriter sw = new StreamWriter(stream);

    sw.AutoFlush = true;
    sw.WriteLine("test");

    List<string> xmlStrings = new List<string>();
    while (sr.Peek() > -1)
        xmlStrings.Add(sr.ReadLine());
    string xmlStr = string.Join("\r\n", xmlStrings.ToArray());

    //this calls stream.Dispose as well internally
    sr.Close();

    //actually, this also calls stream.Dispose(), but fortunately MS made it safe
    sw.Close();

    ProcessXMLResponse(xmlStr);
}

//At this point all IDisposable objects have been disposed of properly (TcpClient, Stream, StreamReader, StreamWriter)
//we minimized the number of stream.Dispose() calls whereas using 3 using blocks (1 for the stream, 1 for the Reader and 1 for the Writer) would have resulted in 3 calls

答案 1 :(得分:0)

让我们看一下StreamReader.Peek in MSDN

  

表示要读取的下一个字符的整数,如果没有要读取的字符,或者如果流不支持,则为-1。

(强调我的)

NetworkStream is not seekable

  

获取一个值,该值指示流是否支持搜索...此属性始终返回false。

基本上,根据文档,你的代码被破坏了;当有数据随时可用时(这与小型和大型有效负载描述一致),我猜测它正在工作,但是当数据不能立即可用时就会失败。

基本上,请勿在此使用Peek。只需读取数据,直到用完为止。如果您想最小化代码更改:

List<string> xmlStrings = new List<string>();
string line;
while((line = sr.ReadLine()) != null)
    xmlStrings.Add(line);

但我个人会以非常不同的方式实现它。