Sending and Receiving Data

Sending and Receiving Data

Sending and receiving data in .NET sockets is really simple. Once you have created a Socket object, you can use the Send, SendTo, Receive, and ReceiveFrom methods, which are similar to the send, sendto, recv, and recvfrom Winsock 1 APIs. There are several overloaded versions of these send and receive methods. Each one sends and receives data using a simple byte type array.

I/O Methods

.NET Sockets has three basic I/O methods to manage data and connections on a socket: blocking, select, and asynchronous. These resemble some of the I/O methods described in Chapter 5.

Blocking I/O

Blocking I/O is the simplest model to use. Anytime you call an I/O-bound .NET Sockets method, such as Receive, when there is no data pending on the receiving socket, the call will do just that—block. If you need your application to do other things or to service additional socket requests, you will have to create additional threads in your application. If your application is just a simple client handling one connection, blocking sockets is a good I/O model to use. The following code fragment demonstrates how to develop a simple client application that can connect to a server and send a simple string using blocking I/O on the Connect and Send calls. This sample can be found on the companion CD in the TCPClient directory.

System.Net.IPAddress ServerAddress =      System.Net.IPAddress.Parse("136.149.3.29"); System.Net.IPEndPoint ServerEndPoint = new      System.Net.IPEndPoint(ServerAddress, 5150); System.Net.Sockets.Socket MySocket = new Socket( AddressFamily.InterNetwork,  SocketType.Stream,  ProtocolType.IP); MySocket.Connect(ServerEndPoint); String s = "Hello - This is a test"; Byte[] buf = System.Text.Encoding.ASCII.GetBytes(s.ToCharArray()); int BytesSent = MySocket.Send(buf); System.Console.WriteLine("Successfully sent " +      BytesSent.ToString() + " byte(s)"); MySocket.Shutdown(System.Net.Sockets.SocketShutdown.Both); MySocket.Close();

If you plan to develop an application that manages multiple sockets, we suggest using one of our next two models, Select or Asynchronous, instead of creating multiple threads.

Select I/O

With the limitations of blocking I/O for managing multiple sockets, .NET Sockets features a Select method that is similar to the Select Winsock 1 API that allows managing multiple socket I/O from one execution thread. Essentially, you can provide Select with a list of sockets to test for readability, writeabilty, and OOB data. The following code fragment demonstrates how to test sockets for readability:

// Assume we have 2 connected sockets - Socket1 and Socket2 Socket[] ReadList = new Socket[2]; ReadList[0] = Socket1; ReadList[1] = Socket2;  Socket.Select(ReadList, null, null, 100000); // When Select returns either by our timeout // value 100000 or if data is pending on one // of our sockets, the ReadList will contain // only those sockets that need to be read. for (int i = 0; i < ReadList.Length; i++) { byte [] Buffer = new byte[1024]; // Receive data from the returned socket; ReadList[i].Receive(Buffer); }

Although Select can manage multiple sockets from a single thread, we highly recommend using our next model—asynchronous—especially if you are developing a high-performance server. For more information about using the Winsock select API, see Chapter 5.

Asynchronous I/O

The asynchronous model in .NET sockets is the best way to manage I/O from one or more sockets. It is the most efficient model of the three because its design is similar to the I/O completion ports model (described in Chapter 5) and on Windows NT–based systems it will use the completion port I/O model internally. Because of this, you can potentially develop a high-performance, scalable Winsock server in C# and even possibly in Visual Basic. For a complete discussion of how to develop a high-performance, scalable Winsock application, see Chapter 6.

In Table 13-2 we described several methods that may be used to process I/O asynchronously: BeginAccept, EndAccept, BeginConnect, EndConnect, BeginReceive, EndReceive, BeginSend, EndSend, BeginSendTo, and EndSendTo. Notice how each one of these methods has a “BeginXXX”-“EndXXX” pair for each of the major I/O-bound socket methods—Accept, Connect, Receive, Send, and SendTo.

To call one of the I/O socket methods asynchronously, you must call the “BeginXXX” method counterpart and supply a delegate (or callback) method in the “BeginXXX” call. When the “BeginXXX” call completes, your calling thread may continue processing other things while your supplied delegate method internally waits for I/O to complete. When the socket has completed your I/O operation, your delegate method is called to process the completed I/O results. Inside your delegate method, you can retrieve the completed I/O results using the EndXXX counterpart method.

For example, let's describe how to process a Receive call asynchronously. We chose Receive because it is one of the most common methods that can cause your application to block when you wait for data to arrive on a socket. To call Receive asynchronously, you must call BeginReceive, which is defined as

public IAsyncResult BeginReceive(    byte[] buffer,    int offset,    int size,    SocketFlags socketFlags,    AsyncCallback callback,    object state );

Most of the parameters are similar to the Winsock recv API except for the callback and state parameters. The callback parameter accepts a delegate method that is used to handle the completed results of the asynchronous BeginReceive. The delegate method must have the following form:

public delegate void AsyncCallback(    IAsyncResult ar ); 

The ar parameter is an input parameter that receives an IAsyncResult object, which you can pass to the EndReceive counterpart method (alternatively, you can use the IAsyncResult object that is returned from the originating BeginReceive call). Also, IAsyncResult contains an important member variable, AsyncState, which contains per-I/O data that was originally passed in the state parameter of the originating BeginReceive call. Typically, you will use this per-I/O data object to pass buffer and socket information that is related to the receive call.

Once your delegate method is called after BeginReceive has completed, you should call EndReceive to retrieve the results of the asynchronous Receive, which is defined as

public int EndReceive(    IAsyncResult asyncResult );

EndReceive returns the number of bytes received in the buffer that was originally passed to BeginReceive. Once you have the completed results, you can begin processing the data received in the buffer.

note

When you call BeginReceive, BeginReceiveFrom, BeginSend, or BeginSendTo, you are not allowed to access the supplied buffer until your delegate method has been called indicating that the asynchronous method has completed.

The following code fragment demonstrates how to call Receive asynchronously using BeginReceive and EndReceive. On the companion CD we have provided a sample called TCPServer that demonstrates how to call Accept, Receive, and Send asynchronously on a TCP socket.

// Assume we have a connected socket named MySocket PerIOData PData; PData.s = MySocket; public AsyncCallback AsyncReceiveCallback = new  AsyncCallback(ProcessReceiveResults); MySocket.BeginReceive(PData.Buffer, 0, PData.Buffer.Length,  SocketFlags.None, AsyncReceiveCallback, PData); public static void ProcessReceiveResults(IAsyncResult ar) { PerIOData PData = (PerIOData) ar.AsyncState; int BytesReceived = PData.s.EndReceive(ar);    // Do something about your received results    . . .  } public class PerIOData {    // Put whatever data you need here for the delegate method.    // Most applications will probably define the data buffer    // here for the received data.    byte [] Buffer = new byte[4096];    Socket s;    . . .  }



Network Programming for Microsoft Windows
Network Programming for Microsoft Windows (Microsoft Professional Series)
ISBN: 0735605602
EAN: 2147483647
Year: 2001
Pages: 172
Authors: Anthony Jones

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