2012-06-15 3 views
0

Я использую стороннюю библиотеку сокетов, хотя это несколько не имеет отношения к моему вопросу. Библиотека состоит из класса «Socket» с такими методами, как «ConnectAsync» и «WriteAsync». Управление возвращает сразу после вызова одного из этих методов, и класс сокета вызывает события для уведомления, когда операция завершена, например. «ConnectCompleted» и «WriteCompleted». Класс также вызывает событие при получении данных: «PacketArrived».C# как обернуть управляемый событиями код с обратными вызовами

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

SocketHelper.SendData(dataToSend, myCallback); 

Где " myCallback "вызывается, когда данные получены.

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

+0

Начните читать праймер на событиях C# и делегатах http: //www.akadia.com/services/dotnet_delegates_and_events.html Я думаю, что обертка библиотеки может быть мостом слишком далеко, вам не нужно проходить обратные вызовы с помощью механизма событий .NET. –

+1

Какая версия рамки? .NET 4 имеет параллельную библиотеку задач, чтобы помочь с такими проблемами –

+0

@PanagiotisKanavos это .Net 4 –

ответ

2

Stephen Toub обсуждает эту тему для .NET 4.5 в «Awaiting Socket Operations». С небольшим количеством работы вы можете использовать тот же метод для .NET 4.

Вместо использования обратных вызовов вы можете использовать параллельную библиотеку задач до simplify asynchronous calls. Используя TPL, вы можете преобразовать все операции сокета и обратные вызовы в задачи, которые вызывают операции и обрабатывают результаты.

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

Задачи выполняются с использованием потоков из пула потоков, поэтому вам не нужно заниматься резьбой.

TPL уже предоставляет способ создания задач из пар функций BeginXXX/EndXXX или объектов IAsyncResult. Если ваша библиотека сокетов предоставляет их, вы можете сразу начать использовать Задачи.

Для работы с событиями вы можете использовать источник TaskCompletion из параллельной библиотеки задач для создания задачи, которая запускается при вызове метода сокета и завершается только при создании соответствующего события. Методика описана в «Tasks and the Event-based Asynchronous Pattern»

Библиотека ParallelExtensionsExtras использует этот метод для предоставления асинхронных версий методов для WebClient, SmtpClient and Ping.

Использование кода из «Задачи и EAP», можно написать методы расширения для вашего класса сокета, как это:

public static Task ConnectTask(this Socket socket, object address) 
{ 
    var tcs = CreateSource(address); 
    socket.ConnectCompleted += 
     (sender, e) => TransferCompletion(tcs, e,() => e.Result, null); 
    socket.ConnectAsync(address, tcs); 
    return tcs.Task; 
} 

И использовать его как это:

var connectTask=mySocket.ConnectTask(myaddress); 
connectTask.ContinueWith(t=> { ... }); 

Вещи становятся еще проще в .NET 4.5. Асинхронные/ожидающие ключевые слова позволяют избавиться от вызовов ContinueWith и писать код, который очень похож на его синхронную версию. Вы можете проверить «Awaiting Socket Operations» для расширений специально для сокетов.

+0

TaskCompletionSource отлично звучит. Библиотека сокетов предоставляет только события (без методов Begin/EndXxxx). Большое спасибо. –