Асинхронный XmlReader в.NET?

Существует ли способ получить доступ к XmlReader асинхронно? xml входит от сети от многих различных клиентов как в XMPP; это - постоянный поток <action>...</action> теги.

Что я, после должен смочь использовать интерфейс BeginRead/EndRead-like. Лучшее решение, которое мне удалось предложить, состоит в том, чтобы сделать асинхронное чтение для 0 байтов на потоке базовой сети, затем когда некоторые данные прибывают, назовите Чтение на XmlReader-, который это однако заблокирует, пока все данные из узла не становятся доступными. То решение примерно походит на это

private Stream syncstream;
private NetworkStream ns;
private XmlReader reader;

//this code runs first
public void Init()
{
    syncstream = Stream.Synchronized(ns);
    reader = XmlReader.Create(syncstream);
    byte[] x = new byte[1];
    syncstream.BeginRead(x, 0, 0, new AsynchronousCallback(ReadCallback), null);
}

private void ReadCallback(IAsyncResult ar)
{
    syncstream.EndRead(ar);
    reader.Read(); //this will block for a while, until the entire node is available
    //do soemthing to the xml node
    byte[] x = new byte[1];
    syncstream.BeginRead(x, 0, 0, new AsynchronousCallback(ReadCallback), null);
}

Править: Это - возможный алгоритм для разработки, если строка содержит полный xml узел?

Func<string, bool> nodeChecker = currentBuffer =>
                {
                    //if there is nothing, definetly no tag
                    if (currentBuffer == "") return false;
                    //if we have <![CDATA[ and not ]]>, hold on, else pass it on
                    if (currentBuffer.Contains("<![CDATA[") && !currentBuffer.Contains("]]>")) return false;
                    if (currentBuffer.Contains("<![CDATA[") && currentBuffer.Contains("]]>")) return true;
                    //these tag-related things will also catch <? ?> processing instructions
                    //if there is a < but no >, we still have an open tag
                    if (currentBuffer.Contains("<") && !currentBuffer.Contains(">")) return false;
                //if there is a <...>, we have a complete element.
                //>...< will never happen because we will pass it on to the parser when we get to >
                if (currentBuffer.Contains("<") && currentBuffer.Contains(">")) return true;
                //if there is no < >, we have a complete text node
                if (!currentBuffer.Contains("<") && !currentBuffer.Contains(">")) return true;
                //> and no < will never happen, we will pass it on to the parser when we get to >
                //by default, don't block
                return false;
            };
7
задан KJ Tsanaktsidis 16 February 2010 в 11:05
поделиться

4 ответа

XmlReader буферизует блоки по 4 КБ, если я помню, когда я заглядывал в это пару лет назад. Вы можете дополнить свои входящие данные до 4 КБ (ick!) Или использовать лучший парсер. Я исправил это, перенеся XP (Java) Джеймса Кларка на C # как часть Jabber-Net, здесь:

http://code.google.com/p/jabber-net/source/browse/#svn/trunk / xpnet

Это LGPL, обрабатывает только UTF8, не упакован для использования и почти не имеет документации, поэтому я бы не рекомендовал его использовать. :)

2
ответ дан 7 December 2019 в 05:22
поделиться

Это действительно сложно, потому что XmlReader не предоставляет асинхронного интерфейса.

Я не совсем уверен, насколько асинхронно ведет себя BeginRead , когда вы просите его прочитать 0 байтов - с таким же успехом он может немедленно вызвать обратный вызов, а затем заблокировать его при вызове Read .Это может быть то же самое, что и прямой вызов Read , а затем планирование следующего Read в пуле потоков, например, с помощью QueueWorkItem .

Возможно, лучше использовать BeginRead в сетевом потоке для чтения данных, например, блоками по 10 КБ (пока система ожидает данных, вы не будете блокировать ни один поток). Когда вы получаете фрагмент, вы должны скопировать его в некоторый локальный MemoryStream , и ваш XmlReader будет читать данные из этого MemoryStream .

Это все еще имеет проблему - после копирования 10 КБ данных и нескольких вызовов Read последний вызов будет заблокирован. Тогда вам, вероятно, потребуется скопировать меньшие фрагменты данных, чтобы разблокировать ожидающий вызов Read . Как только это будет сделано, вы можете снова запустить новый вызов BeginRead для асинхронного чтения большей части данных.

Честно говоря, это звучит довольно сложно, поэтому мне очень интересно, найдет ли кто-нибудь лучший ответ. Однако он дает вам по крайней мере некоторые гарантированные асинхронные операции, которые занимают некоторое время и при этом не блокируют никакие потоки (что является важной целью асинхронного программирования).

( Примечание: Вы можете попробовать использовать F # асинхронные рабочие процессы , чтобы написать это, потому что они значительно упрощают асинхронный код.Однако описанная мною техника будет сложной даже в F #)

1
ответ дан 7 December 2019 в 05:22
поделиться

Проще всего поместить его в другой поток , возможно, ThreadPool, в зависимости от того, как долго он остается активным. (Не используйте потоки пула потоков для действительно длительных задач).

2
ответ дан 7 December 2019 в 05:22
поделиться

Вы ищете что-то вроде метода XamlReader.LoadAsync?

Асинхронная операция загрузки XAML первоначально возвращает объект, который исключительно корневой объект. Затем асинхронно продолжается разбор XAML. продолжается, и все дочерние объекты заполняются под корнем.

0
ответ дан 7 December 2019 в 05:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: