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);
}