WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Using .NET Sockets

by Budi Kurniawan coauthor of VB.NET Core Classes in a Nutshell
10/21/2002

Writing programs that access the network used to be a relatively difficult task. With .NET, this is no longer the case. The .NET Framework class library includes two namespaces that are full of classes that help you with networking: System.Net and System.Net.Sockets. In this article, I will discuss one of the most important classes in System.Net.Sockets: the Socket class. The System.Net.Sockets.Socket class can be used as a socket in a server application as well as in a client application. It also allows both synchronous and asynchronous operations. This article shows how to use the Socket class in a client application.

A socket is an endpoint of a connection. It is a descriptor that lets an application read from and write to the network. With sockets, client and server applications can communicate by sending and receiving streams of bytes over connections. To send a message to another socket used in a software application, you need to know not only the machine's IP address that hosts the software application, but also the software's process identifier on that machine. The identification of a software process in a machine is achieved through the use of a unique number called port. Therefore, to send a message from a socket in one application to another socket at the other end of a connection, you need to know the machine's IP address and the application's port number. In the .NET Framework, a socket is represented by the System.Net.Sockets.Socket class. This class is an implementation of the Sockets API, which is also known as the Berkeley sockets interface. The Sockets API was developed in the early 80s at the University at Berkeley for the 4.1c release of Berkeley Software Distribution (BSD) Unix. This distribution contained an early version of the Internet protocols.

Related Reading

VB.NET Core Classes in a Nutshell
By Budi Kurniawan, Ted Neward

Constructing a Socket Object

The Socket class provides the following constructor for you to use to create a Socket object.



public Socket (AddressFamily addressFamily, 
               SocketType socketType, 
               ProtocolType protocolType ); 
               

Instantiating a Socket object requires you to pass three arguments to its constructor: AddressFamily, SocketType, and ProtocolType, all of which are enumerations that are part of the System.Net.Sockets namespace. An AddressFamily member defines the addressing scheme that a Socket object uses to resolve an address. For socket applications that will work on the Internet, you use InterNetwork.

SocketType determines the type of socket. The most popular socket type is Stream. This type of socket supports two-way connection-based byte streams. ProtocolType specifies the type of the low-level protocol that the socket uses to communicate. A stream socket must be used with the Transmission Control Protocol (TCP) protocol type and the InterNetwork address family. For example, the following code instantiates a Socket object.



Socket mySocket = new Socket(AddressFamily.InterNetwork, 
                             SocketType.Stream, 
                             ProtocolType.Tcp); 


The arguments you pass to the constructor are available in the following read-only properties: AddressFamily, SocketType, and ProtocolType.

Connecting to A Remote Server

Once you have a socket instance, you can connect to a remote server using the Connect method of the Socket class. This method attempts to connect to a remote server synchronously. It waits until a connection attempt is successful or failed before releasing control to the next line in the program. Even though this method is easy to use, there is some preliminary work youneed to do before you can use this method to connect to a remote server. Consider the signature of the Connect method below.



public void Connect( EndPoint remoteEP); 

It accepts an argument: an instance of System.Net.EndPoint. The abstract EndPoint represents a network address. It has a subclass: System.Net.IPEndPoint. When using the Connect method, you typically pass an IPEndPoint object containing the IP address and port number of the remote server to which you want to connect. The question will then be, "How do you construct an IPEndPoint object for your socket to connect to a remote server?" Now, look at the IPEndPoint class definition. It has two constructors.



public IPEndPoint(long address, int port); 
public IPEndPoint(IPAddress address, int port); 

Of these two constructors, the second is normally used because IP addresses are often represented in dotted-quad notation (such as 129.36.129.44) and, as we soon will see, in .NET socket programming, it is easier to get an IP address in this notation than in a long address. However, the two constructors are actually very similar. It's just that the remote IP address in the first constructor is a long address, whereas in the second constructor, it is a System.Net.IPAddress object. Whichever constructor you choose, you need to have an IP address and the port number of the remote server. The port number is usually not a problem, because popular services are allocated default port numbers. For instance, HTTP uses port 80, Telnet uses port 25, and FTP uses port 21. The IP address is not normally directly available because it is easier for us to remember domain names such as microsoft.com or oreillynet.com rather than the IP addresses mapped to them. With this in mind, we need to resolve a domain name to obtain the IP address of the remote server to which we'd like to connect. In this event, to obtain an IPAddress instance that you can use to connect to a remote server, you need the following other classes: System.Net.Dns and System.Net.IPHostEntry. The Dns class is a final class that retrieves information about a specific host from the Internet Domain Name System (DNS), hence the name Dns. It is mainly used for its Resolve method, to obtain a set of IP addresses mapped to a domain name. The Resolve method returns an IPHostEntry object that contains an array of IP addresses. To obtain these IP addresses, you use the IPHostEntry class' AddressList property. For example, the following code displays all IP addresses mapped to a DNS name.



using System.Net.Sockets; 
using System.Net; 

try 
{ 
  String server = "microsoft.com"; // or any other domain name 
  
  IPHostEntry hostEntry = Dns.Resolve(server); 
  IPAddress[] ipAddresses = hostEntry.AddressList; 
  
  Console.WriteLine(server + " is mapped to:"); 

  foreach (IPAddress ipAddress in ipAddresses) 
  { 
    Console.WriteLine(ipAddress.ToString()); 
  } 
} 
catch (Exception e) 
{ 
  Console.WriteLine(e.ToString()); 
} 

When run, the code will display all IP addresses mapped to the DNS name microsoft.com. If a DNS name is mapped to more than one IP address, you can use any of those addresses, even though people normally use the first one. The reason for choosing the first one is because a DNS name is often mapped to one IP address only. Obtaining the first IP address mapped to a DNS name is achieved using the following code:

HostEntry.AddressList[0] 

What's more important, once you get an IPAddress object, you can construct an IPEndPoint object to connect to a remote server. If the connection is successful, the Socket instance will set its Connected property to true. A programmer often checks the value of this property before performing other operations on the socket instance, because a server application can close a connection after a period of time lapses. To close a connection explicitly when you are done with a socket, you use the Close method. Normally, you need to call the Shutdown method prior to invoking Close to flush all pending data.

Sending and Receiving Streams

After your socket is connected to a remote machine, you can send and receive data. To send data in synchronous mode, you use the Send method. The data you send must be placed in an array of bytes. There are four overloads of the Send method, all of which return an Integer indicating the number of bytes sent. The first overload is the simplest and the easiest to use of the four. It has the following signature:



public int Send(byte[] buffer); 

where buffer is an array of bytes containing the data you want to send. Using this overload, all data in the buffer will be sent. The second overload allows you to send all data in the buffer and specify the bitwise combination of the System.Net.Sockets.SocketFlags enumeration members. It has the following signature:



public int Send(byte[] buffer, SocketFlags socketFlags); 

The third overload allows you to send all or part of the data in the buffer and specify the bitwise combination of the SocketFlags enumeration.



public int Send( byte[] buffer, int size, SocketFlags socketFlags ); 

In this overload, size is the number of bytes to be sent.

The last overload is similar to the third overload, but it also allows you specify an offset position in the buffer to begin sending data. Its signature is as follows:



public int Send( byte[] buffer, int offset, int size, SocketFlags socketFlags ); 

In this overload, offset is the offset position. To receive data synchronously, you use the Receive method. This method also has four overloads, which are similar to the Send method overloads. The signatures of the overloads are as follows:



public int Receive(byte[] buffer); 
public int Receive(byte[] buffer, SocketFlags socketFlags); 
public int Receive( byte[] buffer, int size, SocketFlags socketFlags ); 
public int Receive( byte[] buffer, int offset, int size, SocketFlags socketFlags ); 
      

When using the Receive method, you can use the Socket class' Available property, which specifies the number of bytes of data received and is available to be read.

Summary

This article introduced the System.Net.Sockets.Socket class and some other supporting classes from the System.Net namespace. Socket is used to easily access the network from your .NET application. You have also learned how to instantiate a Socket object and how to send and receive streams.

Budi Kurniawan is a senior J2EE architect and author.

Return to ONDotnet.com