套接字流不包含整个响应

本文关键字:响应 包含整 套接字 | 更新日期: 2023-09-27 18:15:36

在我的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,即使数据尚未全部被接收。

你知道是什么问题吗?

套接字流不包含整个响应

如果你尝试使用

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

让我们看看MSDN中的StreamReader.Peek:

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

(强调我的)

NetworkStream不可寻:

获取一个值,该值指示流是否支持查找…此属性总是返回false。

基本上,根据文档,你的代码是坏的;我猜它是工作时,有数据随时可用(这将是一致的小vs大有效载荷的描述),但失败时,数据不是立即可用。

基本上,这里不要使用Peek。只要读取数据,直到用完为止。如果您想尽量减少代码更改:

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