मैं एपीआई को साफ करने के लिए टीपीएल के साथ निम्नलिखित डेटाग्राम सॉकेट ऑपरेशन को लपेटना चाहता हूं ताकि यह async
और await
के साथ अच्छी तरह से काम करे, StreamSocket
वर्ग की तरह।मैं datagramSocket.Message को एसिंक/प्रतीक्षा के साथ उपयोग के लिए कैसे प्राप्त कर सकता हूं?
public static async Task<bool> TestAsync(HostName hostName, string serviceName, byte[] data)
{
var tcs = new TaskCompletionSource<bool>();
var socket = new DatagramSocket();
socket.MessageReceived += (sender, e) =>
{
var status = false; // Status value somehow derived from e etc.
tcs.SetResult(status);
};
await socket.ConnectAsync(hostName, serviceName);
var stream = await socket.GetOutputStreamAsync();
var writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
return tcs.Task;
}
चिपका बिंदु MessageReceived
घटना है जो घटना अतुल्यकालिक पैटर्न का एक अजीब उलझन और नए async
पैटर्न में DatagramSocket
वर्ग बदल जाता है। वैसे भी, TaskCompletionSource<T>
मुझे बाद वाले के अनुरूप हैंडलर को अनुकूलित करने की अनुमति देता है, इसलिए यह बहुत डरावना नहीं है।
यह तब तक बहुत अच्छा काम करता है जब तक कि एंडपॉइंट कभी भी कोई डेटा न लौटाए। MessageReceived
हैंडलर से जुड़ा कार्य कभी पूरा नहीं होता है और इस प्रकार TestAsync
से कार्य वापस नहीं आता है।
टाइमआउट और रद्दीकरण को शामिल करने के लिए इस ऑपरेशन को अच्छी तरह से लपेटने का सही तरीका क्या है? मैं इस फ़ंक्शन को बाद में के लिए CancellationToken
तर्क लेने के लिए विस्तारित करना चाहता हूं, लेकिन मैं इसके साथ क्या करूँ? केवल एक चीज मैं ले कर आए हैं एक अतिरिक्त "निगरानी" कार्य का उपयोग कर Task.Delay
जो मैं एक टाइमआउट मान और रद्द करने टोकन निम्नलिखित लाइनों के साथ इन दोनों व्यवहार का समर्थन करने के पारित करने के लिए बनाने के लिए है:
public static async Task<bool> CancellableTimeoutableTestAsync(HostName hostName, string serviceName, byte[] data, CancellationToken userToken, int timeout)
{
var tcs = new TaskCompletionSource<bool>();
var socket = new DatagramSocket();
socket.MessageReceived += (sender, e) =>
{
var status = false; // Status value somehow derived from e etc.
tcs.SetResult(status);
};
await socket.ConnectAsync(hostName, serviceName);
var stream = await socket.GetOutputStreamAsync();
var writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
var delayTask = Task.Delay(timeout, userToken);
var t1 = delayTask.ContinueWith(t => { /* Do something to tcs to indicate timeout */ }, TaskContinuationOptions.OnlyOnRanToCompletion);
var t2 = delayTask.ContinueWith(t => { tcs.SetCanceled(); }, TaskContinuationOptions.OnlyOnCanceled);
return tcs.Task;
}
हालांकि, इसमें देरी कार्य और MessageReceived
हैंडलर के बीच संभावित दौड़ स्थितियों सहित सभी प्रकार की समस्याएं हैं। मैं इस दृष्टिकोण को विश्वसनीय रूप से काम करने में कभी भी सक्षम नहीं हुआ हूं, साथ ही यह हास्यास्पद रूप से जटिल और थ्रेड पूल के अक्षम उपयोग के रूप में लगता है। यह बदसूरत है, त्रुटि प्रवण है और मेरे सिर दर्द होता है।
साइड नोट: क्या मैं अकेला व्यक्ति हूं जो DatagramSocket
एपीआई सामान्य रूप से उलझन में है? ऐसा लगता है कि यह IAsyncAction
विनरेट मॉडल और टीपीएल के कुछ बदसूरत ईएपी के साथ एक बदसूरत समूह प्रतीत नहीं होता है, मैं एक एपीआई के साथ बहुत सहज नहीं हूं जिसका उद्देश्य मूल रूप से कनेक्शन रहित प्रोटोकॉल का प्रतिनिधित्व करना है जैसे यूडीपी ConnectAsync
नामक विधियों उन्हें। यह मेरे संदर्भ में एक विरोधाभास प्रतीत होता है।
पूरी दूसरी विधि के बजाय, एक नई विधि बनाएं जो कार्य को पहले कार्य से जोड़ती है। डेले और कार्य का उपयोग करता है। जब भी। एक बार यह लौटने के बाद या तो आपका कार्य पूरा हो गया या टाइमआउट हुआ। –