c # XmlReader с внутренним текстом base64 - PullRequest
0 голосов
/ 13 июля 2011

Хорошо, вот моя проблема. Я пытаюсь сделать снимок экрана, добавить его в xmldocument, отправить через сокет и прочитать его с помощью XmlReader.

Вот код ...

Серверная сторона

private void SendRandomData(object data)
{
    XMLShitSock sock = data as XMLShitSock;
    if(sock != null)
    {
        int incnum = 0;
        while(sock.Connected)
        {
            XmlDocument doc = new XmlDocument();
            XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            doc.AppendChild(docNode);

            XmlNode productsNode = doc.CreateElement("image");

            productsNode.InnerText = Convert.ToBase64String(Program.CaptureImageToBytes(new Point(0, 0), new Rectangle(0, 0, Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height), ImageFormat.Png));
            doc.AppendChild(productsNode);
            string s = XMLShitSock.GetXmlString(doc);
            doc.Save("temp.xml");
            sock.WriteXMLMessage(doc);
            incnum++;
            Thread.Sleep(5000);
        }
    }
}

sock.WriteXMLMessage

public bool WriteXMLMessage(XmlDocument doc)
{
    try
    {
        ShittySocket.Client.Send(Encoding.ASCII.GetBytes(GetXmlString(doc)));
        return true;
    }
    catch(SocketException se)
    {
        this.Close();
        return false;
    }
}

Чтение ввода

private void doInput()
{
    MemoryStream ms = new MemoryStream();
    NetworkStream ns = new NetworkStream(ShittySocket.Client, false);
    while(_connected)
    {
        if(ns.DataAvailable)
        {
            StreamReader sr = new StreamReader(ns);
            char[] b = new char[512];
            int nread = sr.Read(b, 0, 512);

            ms.Write(System.Text.Encoding.ASCII.GetBytes(b, 0, nread), 0, nread);
            ms.Seek(0, System.IO.SeekOrigin.Begin);

            XmlReaderSettings xrs = new XmlReaderSettings();

            XmlReader reader = XmlReader.Create(ms);
            if(reader.Read())
            {
                XmlDocument objXmlDocument = new XmlDocument();
                objXmlDocument.Load(reader);
                onInput(this, objXmlDocument);
                ms.Close();
                ms = new MemoryStream();
            }
        }
        Thread.Sleep(100);
    }
}

Проблема у меня в том, что я получаю сообщение об ошибке в doInput (), говорящее о том, что конец документа был достигнут без поиска тега. Я сохранил XML-файл и просмотрел его, и он существует, и я даже не нашел никаких символов <кроме тех, что есть в реальных тегах, поэтому я не уверен, что здесь происходит. Я явно что-то упускаю. </p>

Кроме того, если у вас есть проблемы с семантикой или стилем кодирования, или с чем-то, что на самом деле не отвечает на вопрос, оставьте это как комментарий, так как это не ответ.

Также Я просмотрел это - >> http://msdn.microsoft.com/en-us/library/system.xml.xmltextreader.readbase64.aspx и надеюсь, что есть лучший способ справиться с данными base64, чем отделить их от самого XMLDocument. Благодаря.

Ответы [ 4 ]

2 голосов
/ 13 июля 2011

Похоже, вы предполагаете, что все данные будут прочитаны в одном 512-байтовом блоке.Поэтому, если фактические данные, скажем, имеют длину 513 байтов, то вы не получите закрывающую угловую скобку> в конце документа, поэтому синтаксический анализатор XML не будет работать.

Я не знаю точно, чтотип сетевого потока, который вы используете, но если это простые ванильные сокеты, то вам нужен какой-то разделитель, чтобы знать, когда вы достигли конца одного «отправки» и начала следующего, потому что ванильные сокеты - это просто конвейерданные.При одном чтении вы могли бы получать половину, один, два, три с половиной фактических блока.

Удобно, у вас есть разделитель в виде закрывающего тега.

1 голос
/ 13 июля 2011

Две вещи относительно doInput():

  1. XmlReaderSettings xrs = new XmlReaderSettings(); не нужны, так как вы не используете их в последующем XmlReader.Create().И в этом не будет необходимости, если вы сначала не установите некоторые его свойства.

  2. Вы не можете предполагать, что reader.Read() прочитает весь XML прямо здесь.С XmlReader вы должны делать Read(), пока не получите false в ответ.

Это также хорошая идея для using(var reader = XmlReader.Create(...)) { ... }, так что все будет хорошо завершено, когда будет сделаночтение.

0 голосов
/ 13 июля 2011

Хорошо, так что я нашел решение. Вот функция

public static XmlDocument GrabXmlDocFromStream(StreamReader reader)
{
    using(MemoryStream ms = new MemoryStream())
    {
        byte b = 0;
        while(!reader.EndOfStream)
        {
            b = (byte)reader.Read();
            ms.WriteByte(b);
            ms.Seek(0, System.IO.SeekOrigin.Begin);

            using(XmlReader xmlreader = XmlReader.Create(ms))
            {
                XmlDocument doc = new XmlDocument();
                try
                {
                    if(Encoding.ASCII.GetChars(new byte[1] { b })[0] == '>')
                    {
                        if(xmlreader.Read())
                        {
                            XmlDocument objXmlDocument = new XmlDocument();
                            objXmlDocument.Load(xmlreader);
                            return objXmlDocument;
                        }
                    }
                }
                catch(XmlException xe) { }
            }
        }
    }
    return null;
}

Вы используете это так

            using(NetworkStream ns = new NetworkStream(ShittySocket.Client, false))
{
            using(StreamReader sr = new StreamReader(ns))
            {
                XmlDocument xdoc = new XmlDocument();
                while(xdoc != null)
                {
                    xdoc = Program.GrabXmlDocFromStream(sr);
                    if(xdoc != null)
                        Program.Handle_Document(xdoc);
                }
            }
}

Вот две другие функции, упомянутые в коде

    public static string GetXmlString(XmlDocument doc)
    {
        StringWriter sw = new StringWriter();
        XmlTextWriter xw = new XmlTextWriter(sw);
        doc.WriteTo(xw);
        return sw.ToString();
    }

    public static void Handle_Document(XmlDocument doc)
    {
        MessageBox.Show(GetXmlString(doc));
    }

Возможно, это не лучшее решение, но я использовал строку if (Encoding.ASCII.GetChars (new byte [1] {b}) [0] == '>'), чтобы я не получил исключение каждый персонаж. Из того, что я понимаю, использование try-catch таким способом - не совсем «правильный» способ решения проблем, но это работает, и я думаю, что могу понести незначительное временное наказание. Любые идеи были бы хорошими, если вы видите что-то не так с этим, дайте мне знать. Благодаря.

0 голосов
/ 13 июля 2011

попробуй

ms.Position = 0; 

вместо

ms.Seek(0, System.IO.SeekOrigin.Begin);

в doInput()

также вы можете попробовать заменить

Encoding.ASCII

с

Encoding.UTF8

или просто замените много кода просто:

    private void doInput()
    {
        NetworkStream ns = new NetworkStream(ShittySocket.Client, false);
        while (_connected)
        {
            if (ns.DataAvailable)
            {
                using (StreamReader sr = new StreamReader(ns, System.Text.Encoding.UTF8))
                {
                        XmlDocument objXmlDocument = new XmlDocument();
                        objXmlDocument.LoadXml(sr.ReadToEnd());
                        onInput(this, objXmlDocument);
                }
            }
            Thread.Sleep(100);
        }
    }
...