You are on page 1of 13

Asynchronous SocketProgramming in C#: Part I

http://www.codeguru.com/csharp/csharp/cs_network/sockets/article.php/c7695

Objective
Theobjectiveof this articleis to demonstrate asocket-based client/server application that will allow two-wayasynchronous communication between aserver and multiple client applications. Because this exampleuses asynchronous methods, the serverapplication does not usethreads to communicate to multiple clients (although internallytheasynchronous communication mechanism uses threads at the OSlevel).

The Difference Between Synchronousand Asynchronous Communication in Network Programming


Thekeydifferencebetween synchronous andasynchronous communicationcan beexplained with an example. Consider aserver application that is listeningon aspecific port toget datafrom clients.In synchronousreceiving,while theserver is waitingto receive data from aclient, if thestream is emptythe main threadwillblock untilthe request fordata is satisfied. Hence, the server cannot do anythingelse until it receives data from the client.If another client attempts to connect to the serverat that time, the servercannot process that request because it is blocked on the first client. This behavior is notacceptableforareal-world application where weneed to support multiple clients at thesametime. In asynchronouscommunication, while theserveris listeningor receiving data from aclient, itcan still process connection requestsfrom otherclients as wellas receivedata from those clients. When aserver is receivingasynchronously,aseparate thread (at theOS level) listens on the socket and will invokeacallback function (specifiedwhen the asynchronous listening was commenced)when asocket event occurs. This callback function in turn willrespond and process that socket event.For example, if theremoteprogram writes somedata to the socket, a"read data event"(callback functionyou specify)is invoked; it knows how to read the data from thesocket at that point. Even though this could be achieved byrunningmultiplethreads, theC# and .NET frameworks providea rich set of functionalities to do asynchronous communications without introducingthecomplexityof threading.

SocketClass
TheSocket class (System.Net.Sockets.Socket) provides aset ofsynchronous and asynchronous methods for synchronous orasynchronous communication. As per the.NET namingconvention, allthe asynchronous methodnames are created byprefixingthe words "Begin"or"End"to thename ofthe synchronousmethods. Themethods prefixed with "Begin"and"End"represent a pair ofasynchronous methods correspondingto a single synchronous method, asshown in the followingtable.

Synchronous Methods Asynchronous Methods


Connect() Receive() BeginConnect() EndConnect() BeginReceive() EndReceive()

ExampleApplication
The exampleshown in this article has two classes,oneimplementing the Socket Server and the other implementingtheSocket Client.

SocketServerImplementation

TheSocket Server application is implemented in theSocketServer class (file name SocketServer.cs). This class has amain Socket object (m_mainSocket) andan arrayof worker Socket objects (m_workerSocket) as members. Themain Socket object does the listeningfor the clients. Oncea clientis connected, themain Socket transfers theresponsibilityto process the transactions related to that particular client toaworker Socket. Then, themain Socket goes back andcontinueslisteningforother clients. BeginAccept() andBeginReceive() arethe two important methods in theSocket class used by the Socket Serverapplication. TheBeginAccept()method has the followingsignature:
publicIAsyncResultBeginAccept( AsyncCallbackcallback, objectstate ); //(1)Function tocallwhena client isconnected //(2)Stateobjecttopreserve socket // info //

Essentially, after callingtheListen()method ofthemain Socket object,youcallthis asynchronous method and specifyacallbackfunction (1), whichyou designated to do the furtherprocessingrelatedto the client connection.Thestateobject (2) can benullin this particular instance. Because this is an asynchronous method, it will return immediatelyand theserver main thread is freeto process other events. Behind thescenes,aseparate thread willstart listeningon that particular socket forclient connections. When aclient requestsa connection, the callback functionyou specifiedwillbeinvoked. Inside the callback function (in the example, the function is named "OnClientConnect()"),you willdo further processingrelated to the clientconnection.
publicvoidOnClientConnect(IAsyncResultasyn) { try { //Herewecomplete/endtheBeginAccept()asynchronouscall //bycallingEndAcc ept()-whichreturnsthereferenceto //anewSocketobject m_workerSocket[m_clientCount]=m_mainSocket.EndAccept(asyn); //LettheworkerSocketdothefurtherprocessingforthe //justconnectedclient WaitForData(m_wor kerSocket[m_clientCount]); //Nowincrementtheclientcount ++m_clientCount; //Displaythisclientconnectionasasta tusmessageontheGUI Stringstr=String.Format("Client#{0}connected", m_clientCount); textBoxMsg.Text=str; //SincethemainSocketisnowfree,itcangobackandwait //forotherclientswhoareattemptingtoconnect m_mainSocket.BeginAccept(newAsyncCallback (OnClientConnect ),null); } catch(ObjectDisposedException) { System.Diagnostics.Debugger.Log(0,"1", "\nOnClientConnection: Sockethasbeenclose d\n"); } catch(SocketExceptionse) { MessageBox.Show(se.Message); } }

The first thingyou do inside the"OnClientConnect()" function is to calltheEndAccept() method on the m_mainSocket memberobject, which will return areferenceto another socket object. You set this object referenceto oneof themembers ofthe arrayof Socket object referencesyou have (m_workerSocket) andalso increment theclient counter. Now, because you haveareferenceto anew socket object that now can do thefurthertransaction with the client, themain Socket (m_mainSocket) is free; hence,you will callits BeginAccept() method again to start waitingforconnection requestsfromother clients.

On theworker socket,you useasimilar strategyto receivethe datafrom the client.In placeof calling BeginAccept()and EndAccept(), hereyoucallBeginReceive() andEndReceive(). This, in anutshell, is theSocket Server implementation. Whileyouaresendingout datato the clients, theserver simplyuses thespecificworkersocket objects to send datato eachclient.

SocketClientImplementation

(Full SizeImage) TheSocket Client application is implemented in theSocketClient class (filename SocketClient.cs). Compared to theserver whereyou haveamain Socket and an arrayof worker Sockets, hereyouonlyhaveasingle Socket object (m_clientSocket). Thetwo important methods in Socket class used bythe Socket Client application arethe Connect() andBeginReceive() methods. Connect() is asynchronous method and is called to connect to aserver that is listeningfor clientconnections. Because this callwillsucceed/fail immediately, depending on whetherthereis an activeserver listeningor not at the specified IPand Port number, asynchronous method is okayfor this purpose. Onceaconnection is established,you callthe BeginReceive() asynchronousfunction to wait for anysocket write activitybythe server. Here, ifyou callasynchronousmethod, the main thread on the clientapplication willblock andyouwillnot be able to send anydata to the serverwhile the client iswaitingfor data from theserver. When thereis anywriteactivityon the socket from theserverend, the internal thread started byBeginReceive() will invokethe callback function ("OnDataReceived()" in this case), which willtake careof the furtherprocessingof thedata written bythe server. When sendingthe datato theserver,you justcallthe Send() method on them_clientSocket object, which will synchronouslywritethe data tothe socket. That is all thereis forasynchronous socketcommunication usingmultiple clients.

Limitations/PossibleImprovements

y y

Up to 10 simultaneous clients aresupported.Youcan easilymodifyand support unlimited number of clients byusing aHashTableinstead of an array. Forsimplicity, when theserver sends out amessage, itis broadcast toallthe connectedclients. This could easilybemodified to send messages to specific clients byusingthe Socket object pertainingto that particular client. When a client is disconnected, proper action is not taken; the client count is not decremented. Thecorrectwaywould beto reuse or releaseresources forother client connections.

Acknowledgement
Even though thecontentofthis article is independentlydeveloped, theexampleprogram used is influenced bythe articleon Socket Programmingin C# byAshish Dhar.

Updateaddedon03/01/2005

Foramore comprehensive example covering topics suchas threadsynchronization, pleasesee Part IIofthisarticle.

About theAuthor
JayanNairis a Senior SoftwareEngineerwith 11+years of experienceworkingwith cutting edgesoftwaretechnologies. Currentlyheis developingthe next generation software applications forthe telecommnunications testingindustry. Jayan's passions: Object Oriented softwaredesignand developingreusable software components. His motto:"if thesoftware you write is not reusable,you arenot writing software, buthardwareinstead". Jayan finished his Masters degreein Computer Sciencefrom VirginiaTech,Blacksburg,VA. His expertise includes, C, C++, Java, J2EE, Visual Basic, C#, ASP.NET and distributed applications. Heis also a Sun Certified Programmer for theJavaPlatform (SCPJ). You can contact him at jnair1998@hotmail.com.

Downloads
yasync_client_server_exe.zip yasync_client_server_src.zip

Asynchronous SocketProgramming in C#: Part II


http://www.codeguru.com/Csharp/Csharp/cs_network/sockets/article.php/c8781/#Client1

Motivation for ThisArticle


Afterthe originalarticleon Asynchronous SocketProgrammingin C#waspublishedby CodeGuru,Ireceived numerous responsesfrom interested readers. Most of them asked for additional features that weremissingin theoriginal example. Theoriginal articlewas intended to show asimplistic examplefor asynchronous socket programming. To keep the simplicityof theoriginalexample, instead of modifyingit,Iam providingamore comprehensiveexamplebyaddingthefeatures requested bythe readers.

Requested FeaturesAdded
This exampleincludes modifications to support the following features: 1. 2. 3. 4. 5. 6. Howto support an unlimited number of clients Howto find which clientsent aparticular message Howto replyor send messages to specificclients Howto find when aparticular client is disconnected Howto get the list of allconnectedclients at anygiven time Arevariables safein AsyncCallback methods?What about thread synchronization?[Updated on 02/01/05]

Other Enhancements
1. On theserver andclient code, the receivebuffer sizeis increased to 1024 instead of a single byte for moreefficiency. 2. Cleanup codeis added aftera client is disconnected. Screen shot of Socket Server:

Screen shot of Socket Client:

HowtoSupportanUnlimited Number ofClients


This was an easyfeatureto add.Inthe original article,an arrayof Socket objects was used to storethe references to theworker sockets. This isnow modified to use anArrayListas shown in the followingcode. (AHashTablealso would haveworked ifyou wanted to useastring instead of an indexto track the connected clients.) Note:Ifyou want to runyourserver foran infinite duration, thereis thepossibilityof overflow oftheinteger value ofthem_clientCountvariable.In such scenarios,you maywant to reconsider usingthis numberingscheme for clients. This examplewillstillwork on such scenarios, as long asyoudon't numberyour clients. But, this issue goes beyond the scopeof this article.

//AnArrayListisusedtokeeptrackofworkersocketsthatare //designedto communicatewitheachconnec tedclient privateSystem.Collections.ArrayListm_workerSocketList= newSystem.Collections.ArrayList(); //Thefollowingvariablewillkeeptrackofthecumulative //totalnumberofclientsconnectedatanytime privateintm_clientCount=0;

HowtoFind WhichClientSenta ParticularMessage


When multiple clients are connected,you mayneed to differentiate between the messages received from different clients. Also, theremaybea reason to send amessagetoaparticular client. You could solve this problem bykeepingtrack ofeachclient byassigning them aserially incremented number as soon as theyare connected to theserver.Hereis the codethat does that:
publicvoidOnClientConnect(IAsyncResultasyn) { try { //Herewecomplete/end theBeginAccept()asynchronouscall //bycalling EndAccept(),whichreturnsthereferencetoa //newSocketobject SocketworkerSocket=m_mainSocket.EndAccept(asyn); //Now,incrementtheclientcountforthisclient ++m_clientCount; //AddtheworkerSocketreferencetotheArrayList //Wewilluse(clientNumber -1)astheindextoaccess //thissocketinthefuture m_workerSocketList.Add(workerSocket); //........ //LettheworkerSocketdothefurtherprocessingforthe //just-connectedclient WaitForData(workerSocket,m_clientCount); //........

Inside theWaitForData() function,you willmakethe actual asynchronouscallto receive the data from theclient as shown below:
publicvoidWaitForData(System.Net.Sockets.Socketsoc, intclientNumber) { try { if(pfnWorkerCallBack==null) { //Specifythecallbackfunctionthatistobeinvokedwhen //thereisanywriteactivitybythe connectedclient pfnWorkerCallBack=newAsyncCallback(OnDataReceived); } SocketPackettheSocPkt=newSocketPacket(soc,clientNumber); //Startreceivinganydatawrittenbytheconnectedclient //asynchronously soc.BeginReceive(theSocPkt.dataBuffer,0, theSocPkt.dataBuffer.Length, SocketFlags.None,

pfnWorkerCallBack, theSocPkt); //........

In theabovecode, the user-defined class SocketPacketis themostcriticalitem. Asyou can see, an object of this class isthe last parameter passed to the asynchronousfunction call BeginReceive(). This object cancontain anyinformation thatyou find useful;itcan beused later, whenyouactuallyreceive thedatafrom theclient. You send (1) theworker socket object and (2)theindexnumberof the client packaged insidethis object. You willretrieve them back whenyouactuallyreceivethe datafromaparticular client. Given below is the definition ofthe SocketPacketclass.
publicclassSocketPacket { //ConstructorthattakesaSocketandaclientnumber publicSocketPacket(System.Net.Sockets.Socketsocket, intclientNumber) { m_currentSocket=socket; m_clientNumber =clientNumber; } publicSystem.Net.Sockets.Socketm_currentSocket; publicintm_clientNumber; //Buffertostorethedatasentbytheclient publicbyte[]dataBuffer= newbyte[1024]; }

In theabovecode, the SocketPacketclass containsthe referenceto a socket,adata buffer of size1024 bytes, andaclient number. This client numberwillbe availablewhenyou actually start receivingdata fromaparticular client. Byusingthis client number,you can identify which client actuallysentthe data. To demonstrate this in the example code, the server will echo back to theclient (after convertingto uppercase)the received message, usingthe correct socket object.

HowtoReplyorSend MessagestoSpecificClients
You might havefiguredoutthis already. This is verysimple to implement. Because the SocketPacket objectcontains the referenceto a particular worker socket,you just use that object to replyto the client. Additonally,you alsocould send anymessageto anyparticular client byusingthe worker socket object stored in theArrayList.

HowtoFindwhenaParticularClientis Disconnected
This is a bit harder to address. Theremaybeotherelegant ways to do this, but hereis a simple way. When a client is disconnected, therewillbea final callto the OnDataReceived() function.If nothingin particular is done, this callwillthrowaSocketException. Whatyou can do hereis to look inside this exception and seewhetherthis was triggeredbythe"disconnection"of a client. Forthis,you willlook at the error codeinsidethe exception object and seewhether it corresponds to 10054.Ifso,you willdo the required action correspondingto the client

disconnection. Hereagain, theSocketPacket object will giveyou the indexnumberof the client that was disconnected.
catch(SocketExceptionse) { if(se.ErrorCode==10054) { stringmsg="Client"+socketData.m_clientNumber+ "Disconnected"+ "\n"; richTextBoxReceivedMsg.AppendText(msg); //Removethereferencetothe workersocketoftheclosed //clientsothatthisobjectwillgetgarbagecollected m_workerSocketList[socketData.m_clientNumber -1]=null; UpdateClientList(); } else { MessageBox.Show(se.Message); } }

//ErrorcodeforConnectionreset //bypeer

HowtoGet the ListofAllConnected ClientsatAnyGiven Time


To show this, adynamiclist is displayed on the server GUIthat willbeupdated (seethe UpdateClientList() function) whenever aclient isconnected or disconnected.

Are VariablesSafe in AsyncCallbackMethods?WhatAboutThread Synchronization?


This is a veryvalid question. Forsimplicity,Iignored this aspect in the first part of this article. Asynchronous programmingusingasynchronous delegates is just amatterof convenience. Whenyouuse asynchronouscalls,you should be awarethat,behind thescenes, you areactuallyusingthreads to achievethe asynchronous natureof thesecalls. The followingpictureshows asimple illustration ofthe interplayof threads involved in this example.

In theabovepicture, the item labeled (1)is themain GUIthread that startswhenyou start the Server application. Thethread labeled (2)starts wheneveranyclient tries to connect to the socket. Thethread labeled (3)spawns when thereis anywrite activitybyanyoneof the connectedclients. In theexample code, theasynchronous functionsOnClientConnect() andOnDataReceived() arecalled bythreads other than the main GUIthread. Anyother functions called insidethese two functions are also invoked bythreads other than the main GUIthread. Threading issues to consider 1. Sharedvariables Anyshared variables thatyou modifyinsidethe shared codementioned abovemustbe protected bysynchronization structures.In this example, the shared variablesyou modifywithin the sharedcode arem_clientCountandm_workerSocketList. You can useverysimplestrategies to protect thesevariables. Them_clientCount variable is an integer variable and hencecan beincremented byusingthe static method within the Interlockedclass as shown below:
//Nowincrementtheclientcountforthisclient //inathreadsafemanner Interlocked.Increment(ref m_clientCount);

Similarly,youcan protect them_workerSocketListmember variable from modification bymultiple threads at the sametime, bycreatingaSynchronized ArrayListas shown below:
privateSystem.Collections.ArrayListm_workerSocketList=

ArrayList.Synchronized(newSystem.Collections.ArrayList());

2. Modifying theGUI Themain GUIthread actuallyowns theGUIcontrols. Hence, in production code, itis not recommended or advisableto access or modifyanyof theGUIcontrols bythreads otherthan themain thread. Whenyou need to updatethe GUI,you should makethe main thread do itforyouas shown in the followingcode:
//Thismethodcouldbecalledbyeitherthemainthreador //anyoftheworkerthreads privatevoidAppendToRichEditControl(stringmsg) { //Checktoseeifthis methodiscalledfromathread //otherthantheonecreatedthecontrol if(InvokeRequired) { //WecannotupdatetheGUIonthisthread. //AllGUIcontrolsaretobeupdatedbythemain(GUI) //thread. //Hence,wewillusetheinvokemethodonthecontrol //thatwillbecalledwhentheMainthreadisf ree //DoUIupdateonUIthread object[]pList={m sg}; richTextBoxReceivedMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit),pList); } else { //Thisisthemainthreadwhichcreatedthiscontrol, //henceupdateitdirectly OnUpdateRichEdit(msg); } } //ThisUpdateRichEditwillberunbackontheUIthread //(usingSystem.EventHandlersignaturesowedon't //needtodefineanewdelegatetypehere) privatevoidOnUpdateRichEdit(stringmsg) { richTextBoxReceivedMsg.AppendText(msg); }

Acknowledgement
PartIIof this articlewasdeveloped to address thequestions and comments I received from readers after publishing PartIof this article. Theexampleprograms used in PartIwhich are further enhanced and extended forPartII,areinfluenced bythearticleon SocketProgrammingin C# byAshish Dhar.

FinalComments
Networkprogrammingisaveryinterestingtopic.TheC# languageprovidesyou with all the tools necessaryto quicklydevelop networked applications. Compared to C++, Java and C# havea richer set of programmingAPIs, which will eliminatemostof the complexities previouslyassociated with networkprogramming.This exampleincorporates all the features

that the readers requested. Even then, use this exampleonlyas a learningtool. Asyou learn more about socket programming,youwillrealizethe necessityto add thread synchronization constructs as wellseetheopportunities for furtheroptimization,to solvethe problem atyour hand. Good luck withyourlearningand thanks for reading.

About theAuthor
JayanNairis a Senior SoftwareEngineerwith 11+years of experienceworkingwith cutting edgesoftwaretechnologies. Currentlyheis developingthe next generation software applications forthe telecommnunications testingindustry. Jayan's passions: Object Oriented softwaredesignand developingreusable software components. His motto: "if thesoftware you write is not reusable,you arenot writing software, buthardwareinstead". Jayan finished his Masters degreein Computer Sciencefrom VirginiaTech,Blacksburg,VA. His expertise includes, C, C++, Java, J2EE, Visual Basic, C#, ASP.NET anddistributed applications. Heis also a Sun Certified Programmer for theJavaPlatform (SCPJ). You can contact him at jnair1998@hotmail.com.

Downloads
yasync_client_server_II_exe.zip yasync_client_server_II_src.zip

You might also like