Hejsan, Peter heter jag, nyregistrerad här. Tänkte höra om någon har några bra ideér kring ett designproblem jag brottas med: Jag är lite nyfiken på kravet att användaren skall kunna avbryta eller förändra en pågående transaktion. Hur länge lever transactionen? På vilket sätt kommer transactionen att synliggöras i din winform? Det finns ju Windows Communication Foundation (WCF) som klarar transaktionshantering med bl.a rollback över tcp och även http om så önskas. Kanske något för dig att titta på? Transaktionen är sas kapslad i protokollet som man använder mot det externa systemet. Initieras alltid interaktivt från applikationen, och har ett tydligt slut. En service är nog rejält overkill, om inte annat pga. deployment (grymt ovan att skriva om sånt här på svenska!). En tråd som lyssnar på nya anslutningar, den som tar emot anslutningar skall ha så lite arbete som vanligt så det första den som lyssnar på anslutningar är att skicka vidare socketen utan att läsa något på den till en tråd som börjar arbeta med datan på socketen. Applikationen tar inte emot anslutningar i detta fallet, utan ansluter till ett annat system. Så jag har bara en socket öppen i taget. Okay, då missade jag kravbilden lite :) Du kan pusha events från din server till en eller flera klienter vilket skulle innebära att du inte behöver göra någon form av ansträngning för detta. Dock är jag inte tillräckligt insatt i vad det är du försöker uppnå för att kunna ge dig bra alternativa vägar. Men du kommer garanterat fixa det :-) Jag har gjort något liknande, när man startade programmet så startade man även upp en socket som låg och lyssnade, den la jag i en egen tråd. När ett meddelande kom in, så la detta meddelande ner i en FIFO-kö och signalerade att det har ankommit ett meddelande som nu ligger i kön.Bra design för WinForms & TCP?
Har en applikation som kommunicerar med ett externt system via sockets. Data kan komma båda förväntat och spontant från det externa systemet. Användaren ska dessutom ha möjlighet att avbryta, eller förändra en pågående transaktion ifrån ett WinForms GUI. Kan alltså inte blocka i tex. en statemachine.
Vill även göra en testbar lösning, har ett femtiotal testfall som måste gå att dra igenom på ett hyggligt strukturerat sätt, varav vissa måste vara interaktiva (extern hårdvara som inte går att simulera).
Vad skulle vara ett lämpligt design pattern? Sv: Bra design för WinForms & TCP?
Skall flödet avbrytas när winformen stängs ner eller skall data fortsättas att tas emot, bara att det inte syns?
Spontant så skulle jag lägga någon sorts av windows services i botten, som ligger och lyssnar efter meddelande över TCP på din specifika port. När ett meddelande sedan kommer så hade jag startat ett event så eventuella lyssnare hade fått information om att ett nytt meddelande har kommit in och sedan låtit de som lyssnar på meddelanden fått fortsätta att bearbeta information. Men det ankommer lite på kraven för applikationen också. Så man behöver mer information från dig angående transactionerna som du skall kunna avbryta och vad skall hända med datan som man får från de externa system.
- MSv:Bra design för WinForms & TCP?
http://msdn.microsoft.com/en-us/magazine/cc163432.aspxSv:Bra design för WinForms & TCP?
Just nu lutar jag mest åt en bakgrundstråd som agerar ungefär som ditt seviceförslag.
Det absolut enklast och renaste hade ju varit om man kunde få events från sin socket. Då kunde man haft en klass som tog emot events från såväl gui som nätverk, och koordinerade allting. Sv: Bra design för WinForms & TCP?
Den kan notifiera gui:t genom ett event eller lägga till eventet i en lista som i sin tur säger till att listan har ändrats.
Det finns lite olika lösningar på hur Servern-tråden skall arbeta (tråden som lyssnar på nya anslutningar), antingen skapas en tråd för varje ny anslutning som dör efter att ha processat datan. Eller så finns det en eller flera workerthreads som betar av socketar från en lista som server-tråden lägger till socketar med data.
Orsaken till att man vill att tråden som lyssnar på nya anslutningar skall ha så lite att göra är att nya anslutningar inte kan tas emot medans servertråden gör det administrativa arbetet, servertråden kanske hänger sig om man har otur och då slutar ju hela programmet att fungera. Om det hade hängt sig i en skapad tråd eller arbetstråd så kan man enkelt stanna den utan att programmet får ett kritiskt stopp.Sv:Bra design för WinForms & TCP?
Sv: Bra design för WinForms & TCP?
Men hmm en tråd som läser data från socketen en som bearbetar den och skickar den till gui via events eller på något annat sätt? :).
Skulle kunna vara en och samma som läser och bearbetar också iof :)Sv:Bra design för WinForms & TCP?
Sv: Bra design för WinForms & TCP?
Jag hade sedan en annan tråd som låg och lyssnade på dessa signaler om att det kommit meddelande till tråden, och när den fick signalen, så började den läsa från kön och började processa meddelande som låg där.
typ så här
public class ListenToSocket(){
public event MessageArrivedEventHandler MessageArrived;
public Queue _IncomingMessageQueue;
public Thread _IncomingMessageThread;
public AutoResetEvent _IncomingMessageQueueEvent;
private void ListenForMessageInItsOwnThread()
{
//-- Keep running this loop forever...
while (true)
{
try
{
//-- Read data.
//-- Here you do your socket magic...
//-- Add incoming message to queue
lock(_IncomingMessageQueueSyncLock)
_IncomingMessageQueue.Enqueue(message);
//-- Signal that the a message has been added to the queue.
_IncomingMessageQueueEvent.Set();
catch (Exception exception)
{
throw exception;
}
}
private void ReadMessageFromQueInItsOwnThread()
{
//-- Keep running this loop forever...
while (true)
{
try
{
//-- wait here until the flag is set that there is a message in the queue
_IncomingMessageQueueEvent.WaitOne();
//-- Read all message until there is no more.
while (_IncomingMessageQueue.Count > 0)
{
//-- Raise the event to listner that a message has arrived, do it here in this thread,
//-- or start a new thread and do it in that thread, it all depends on your chooices...
}
}
catch (ThreadAbortException threadAbortException)
{
//-- Log this error, but don't do anything more, since it's okey that we get thread abort exceptions here
}
catch (Exception exception)
{
throw exception;
}
}
}
Något sådant...
Fördelarna här, är att du har en tråd som bara har som uppgift att lyssna och ta emot meddelande. Och du har dessutom minimerat möjligheten att sänka applikaitonen genom att skicka 1000-tals meddelande till applikation som alla skulle startat en ny tråd för bearbetning. Dessutom så är du säker på att meddelanden kommer att behandlas i den ordning som de kommer in till din applikation.
Nackdelen är att om du tar lång tid på dig att bearbeta information, så kan kön växa och vissa meddelande kanske inte hinner processas inom rimlig tidsgräns.
Även om det är så att applikationen skapar anslutningarna så tycker jag att du bör lägga dels mottagande och sändning av data till socketen, i sin egen tråd så din applikation inte blir hängande av att behöva vänta på svar mellan det att du sänt data tills du får tillbaka den.
Så 1 tråd som ligger och lyssnar på meddelande och lägger dessa i en kö (som bearbetas av 1 eller flera trådar) och 1 tråd som du startar när du skall skicka meddelande från din applikation till ditt externa system, om du vill så kan du även här använda dig av en kö, så du lägger ner ett meddelande på kön, som signalerar att det finns något i kön, och så skickas datan vidare av en annan tråd, som bara ligger och väntar på att det skall komma något i kön.
Mottagningen av datan från dina sockets till din WinForm hanteras via event som reses när något bearbetas från kön.
När det gäller möjligheten att avbryta en transaction, så måste du ju på något sätt se till så din winform inte "låses" undertiden som transactionen körs, var av ovanstående lösning är bra. Sedan handlar det om vilken data som skall skickas till ditt externa system, och vad händer om du får svar samtidigt som du skickar att transactionen skall avbrutas (den är ju redan färdig på det externa systemet då).
- M