C#: Как установить AsyncWaitHandle в Compact Framework?

Я использую TcpClient в одном из моих приложений Compact Framework 2.0. Я хочу получить некоторую информацию от TCP-сервера.

Так как Compact Framework не поддерживает механизмы тайм-аута "большого" фреймворка, я пытаюсь реализовать свой собственный тайм-аут. По сути, я хочу сделать следующее:

IAsyncResult result = networkStream.BeginRead(buffer, 0, size, ..., networkStream);
if (!result.AsyncWaitHandle.WaitOne(5000, false))
  // Handle timeout


private void ReceiveFinished(IAsyncResult ar)
{
  NetworkStream stream = (NetworkStream)ar.AsyncState;
  int numBytes = stream.EndRead(ar);

  // SIGNAL IASYNCRESULT.ASYNCWAITHANDLE HERE ... HOW??
}

Я хотел бы позвонить Set для IAsyncResult.AsyncWaitHandle, но у него нет такого метода, и я не знаю, к какой реализации его привести.

Как установить ручку ожидания? Или это автоматически устанавливается с помощью вызова EndRead? Документация предполагает, что мне нужно позвонить Set себя...

Спасибо за любую помощь!

ОБНОВИТЬ
Кажется, что дескриптор ожидания устанавливается автоматически при вызове EndRead - но это не в документах. Кто-нибудь может это подтвердить?

ОБНОВЛЕНИЕ 2
Написала client.BeginRead в моем примере кода. Конечно, BeginRead называется на NetworkStream...

1 ответ

Решение

Я думаю, что у вас есть недоразумение по поводу асинхронного ввода-вывода с TCP.

Чтобы запустить асинхронный ввод-вывод, вызовите stream.BeginRead().
При обратном вызове вы вызываете EndRead в потоке.

Вы не вызываете BeginRead для TcpClient, как показывает ваш код. Ваше приложение никогда не подает сигнал WaitHandle. Уровень IO будет вызывать ваш обратный вызов, когда будет получен сигнал о ручке ожидания, другими словами, когда произойдет асинхронное чтение.

При обратном вызове обычно вы снова вызываете BeginRead в потоке, если возможно, что вы получите больше данных.

Вы можете увидеть четкий пример в этом ответе.

Перед запуском танца BeginRead/EndRead вы можете выполнить асинхронное соединение на TcpClient - тогда вы должны использовать BeginConnect. Но это сделано только один раз. В качестве альтернативы вам может потребоваться синхронное соединение, и в этом случае вы просто вызываете TcpClient.Connect().

пример кода:

    private class AsyncState
    {
        public NetworkStream ns;
        public ManualResetEvent e;
        public byte[] b;
    }

    public void Run()
    {
        NetworkStream networkStream = ...;
        byte[] buffer = new byte[1024];

        var completedEvent = new ManualResetEvent(false);

        networkStream.BeginRead(buffer, 0, buffer.Length,
                                AsyncRead,
                                new AsyncState
                                {
                                    b = buffer,
                                    ns = networkStream,
                                    e = completedEvent
                                });

        // do other stuff here. ...

        // finally, wait for the reading to complete
        completedEvent.WaitOne();
    }


    private void AsyncRead(IAsyncResult ar)
    {
        AsyncState state = ar as AsyncState;
        int n = state.ns.EndRead(ar);
        if (n == 0)
        {
            // signal completion
            state.e.Set();
            return;
        }

        // state.buffer now contains the bytes read
        // do something with it here...
        // for example, dump it into a filesystem file. 

        // read again
        state.ns.BeginRead(state.b, 0, state.b.Length, AsyncRead, state);
    }
Другие вопросы по тегам