Using Sockets Asynchronously

I l @ ve RuBoard

You should use the connection-oriented TCP protocol if you're building synchronous clients and servers and you want to ensure that data is transmitted successfully between them. TCP comes at a price, though ”sometimes you'll simply want to use the datagram approach of UDP because of its inherently asynchronous nature, despite the lack of guarantees . Let's look at some of the features of sockets under .NET that you can use to build reliable, asynchronous applications and get the best of both worlds .

The Poll and Select Methods

The TCP examples shown earlier created a thread for each client that connected to the server. Threads consume resources, and lots of threads consume lots of resources. Do you know how many concurrent clients a server will be handling at any one moment? A better way is to use the Poll and Select methods of the Socket class, which you can bring into play to multiplex on a single thread.

The Poll method allows you to query the status of a socket to determine what will happen if you attempt to send or receive data using it. You can use it to determine whether an attempt to read or write from the socket will succeed immediately, block, or result in an error. It is primarily useful for TCP sockets. To use it, you specify a timeout in microseconds (you cannot use a TimeSpan with this method) and a mode . The Poll method will wait until the timeout expires , or an operation indicated by the specified mode will not block. For example, to wait for up to two seconds for data to arrive on a socket, you can use this:

 SocketmySocket; booleanreadyToRead=mySocket.Poll(2000000,SelectMode.SelectRead); 

The Boolean value readyToRead , which the Poll method returns, indicates whether some data is available to be read ( true ) or the operation timed out ( false ). The volume of data is not disclosed, however, so a subsequent receive operation might still block if it attempts to read more data than is available. SelectRead can also be used by a server socket to establish whether an accept operation will block ”it will return true if a client is attempting to connect to a socket that is in listen mode. The other values you can specify are SelectWrite and SelectError . The SelectWrite option returns true if data can be sent down the socket without being blocked, and SelectError returns true if the connection has been broken or unexpected out-of- band data is available. If you want to wait indefinitely, set the timeout interval to “1 when you call Poll . Alternatively, you can use 0 to obtain the current status of a socket and return immediately.

The Poll method lets you examine the status of a given socket. You can use the static Select method to determine the condition of a set of sockets. It expects four parameters: a list of sockets to check for readability, a list of sockets to check for writability, a list of sockets to check for errors, and a timeout (again in microseconds). The lists are passed in as IList interfaces; IList is implemented by many of the collection classes of .NET. Here's an example of how you can use the Select method:

 Socketsender1=...; Socketsender2=...; ArrayListsendList=newArrayList(); sendList.Add(sender); sendList.Add(sender2); Socketreceiver1=...; Socketreceiver2=...; ArrayListreceiveList=newArrayList(); receiveList.Add(receiver1); receiveList.Add(receiver2); ArrayListerrorList=newArrayList(); errorList.Add(sender); errorList.Add(sender2); errorList.Add(receiver1); errorList.Add(receiver2); Socket.Select(sendList,receiveList,errorList,2000000); 

This example creates and populates three ArrayList objects ( ArrayList implements IList ), with references to various sockets used for sending and receiving, and then it invokes Select . The call to Select returns after two seconds. The method always waits for the specified duration. When it returns, the contents of the receiveList collection will be populated with sockets from the original array that are ready to be read from. Similarly, the sendList collection will contain only those sockets from the original list that can be written to without blocking, and the errorList collection will contain all the sockets that reported errors. You can specify null for any of the IList parameters, but not for all of them at the same time!

Network Streams

The Select and Poll methods give you a great deal of control over how and when individual sockets are serviced. In many cases, however, they might be too low-level for what you need; code that uses them can become tortuous and involved. The common language runtime does provide a middle ground between spawning a thread dedicated to each socket connection and using Select and Poll on a single thread: the thread pool and stream mechanism (described in Chapter 8).

The Socket class exposes asynchronous versions of many of its methods. For example, you can issue the BeginAccept method to execute Accept asynchronously on a thread from the thread pool. BeginAccept expects an AsyncCallback that references a method to be run when a client connects. This callback should execute EndAccept to obtain the socket created to communicate with the client. (This will block until the accept operation has completed.) Here's an example of using BeginAccept :

 serverSocket.BeginAccept(newAsyncCallback(handleAsyncClientRequest), serverSocket); privatevoidhandleAsyncClientRequest(IAsyncResultar) { //Gettheserversocket,passedastheAsyncStateproperty SocketserverSocket=(Socket)ar.get_AsyncState(); //Waitforclienttoconnect clientSocket=serverSocket.EndAccept(ar); //IssueBeginAcceptagaintoallowmoreclientstoconnect serverSocket.BeginAccept(newAsyncCallback(handleClientRequest), serverSocket); //Send/ReceivedatausingclientSocket } 

When the client has connected, the request can be handled using the same thread obtained from the thread pool to wait for the client. If you want to allow additional clients to connect, you should execute BeginAccept again (in the callback), which will allocate another thread from the pool if one is available. Incidentally, in the preceding code we passed the socket as the last parameter to BeginAccept . This is the user -defined state object that can be examined in the callback using the AsyncState property ( get_AsyncState ) of the IAsyncResult parameter, and provides a convenient way for the new thread to get a handle on the socket being used.

A socket client has the BeginConnect and EndConnect methods available, to create a thread that connects to a socket server asynchronously:

 SocketclientSocket=...; IPEndPointipEndpoint=...; clientSocket.BeginConnect(ipEndpoint,newAsyncCallback(connectCallback), clientSocket); privatevoidconnectCallback(AsyncResultar) { //Waitfortheconnecttocomplete SocketclientSocket=(Socket)ar.get_AsyncState(); clientSocket.EndConnect(ar); //Sendandreceivedata } 

In addition, a client and a server can employ the BeginSend , EndSend , BeginReceive , and EndReceive methods. The parameters of the Begin methods are similar to their synchronous cousins, with the addition of an AsyncCallback argument, which indicates the method to be executed when data is sent or received, and the usual user-defined state object:

 ubyte[]data=...;//datatobesent clientSocket.BeginSend(data,0,data.length,SocketFlags.None, newAsyncCallback(sendCallback),clientSocket); privatevoidsendCallback(IAsyncResultar) { //Waitforthesendtocomplete SocketclientSocket=(Socket)ar.get_AsyncState(); intnumBytesSent=clientSocket.EndSend(ar); } 

The End methods block until the operation has completed, and they return the number of bytes sent or received as appropriate.

For connectionless socket applications, there are the methods BeginSendTo and BeginReceiveFrom , as well as EndSendTo and EndReceiveFrom .

I l @ ve RuBoard


Microsoft Visual J# .NET (Core Reference)
Microsoft Visual J# .NET (Core Reference) (Pro-Developer)
ISBN: 0735615500
EAN: 2147483647
Year: 2002
Pages: 128

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net