C #: Как установить AsyncWaitHandle в Compact Framework? - PullRequest
1 голос
/ 16 марта 2010

Я использую 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 ...

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

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

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

1 Ответ

2 голосов
/ 18 марта 2010

Я думаю, что вы неправильно понимаете асинхронный ввод-вывод с 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);
    }
...