Working with Sockets


A socket is an end point of a connection. It is a descriptor that lets an application read from and write to the network. Using sockets, client applications 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 Internet Protocol (IP) address that hosts the software application but also the software's process identifier in that machine. A unique number, called a port, identifies a software process in a machine. Therefore, to send a message from a socket in one application to another socket in another connection, you need to know the machine's IP address and the application's port number.

In the .NET Framework, the System.Net.Sockets.Socket class represents a socket. This class is an implementation of the Sockets Application Programming Interface (API), which is also known as the Berkeley sockets interface. The Sockets API was developed in the early 80s at the University of California at Berkeley for the 4.1c release of Berkeley Software Distribution (BSD) Unix. This distribution contained an early version of the Internet protocols.

You can use the System.Net.Sockets.Socket class as a socket in a server application as well as in a client application. It also allows both synchronous and asynchronous operations. This chapter only covers using the Socket class in a client application. For more details on using this class in a server application, you should consult the .NET Framework documentation.

Instantiating a Socket Object

Instantiating a socket object requires you to pass three arguments to its constructor.

 Public Sub New( _   ByVal addressFamily As AddressFamily, _   ByVal socketType As SocketType, _   ByVal protocolType As ProtocolType _ ) 

AddressFamily, SocketType, and ProtocolType 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. For this FTP client application, you will use the Stream type. 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. You must use a stream socket with the Transmission Control Protocol (TCP) type and the InterNetwork address family.

Therefore, instantiating a Socket object for your application requires the following code:

 Dim mySocket As 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 Socket class's Connect method. The Connect method attempts to connect to a remote server synchronously. It waits until a connection attempt is successful or has failed before releasing control to the next line in the program. Even though this method is easy to use, there is some preliminary work before you can use this method to connect to a remote server. Consider the Connect method signature:

 Public Sub Connect( ByVal remoteEP As EndPoint) 

It accepts an argument: an instance of System.Net.EndPoint.

The abstract EndPoint class represents a network address and 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 Sub New( ByVal address As Long, ByVal port As Integer) Public Sub New( ByVal address As IPAddress, ByVal port As Integer) 

Of these two constructors, the second is usually used because IP addresses are dotted-quad notation such as 129.36.128.44 and, as you soon will see, in the .NET socket programming, it is easier to get an IP address in this notation than a Long. However, the two constructors are actually similar. It is just that the remote IP address in the first constructor is a Long, 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 to remember domain names such as microsoft.com or amazon.com rather than the IP addresses mapped to them. With this in mind, you need to resolve a domain name to obtain the IP address of the remote server to which you would like to connect. In the event, to obtain an IPAddress instance that you can use to connect to a remote server, you need the following two 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's AddressList property.

For example, the following code displays all IP addresses mapped to a DNS name:

 Try   Dim server As String = "microsoft.com" 'or any other domain name   Dim hostEntry As IPHostEntry = Dns.Resolve(server)   Dim ipAddresses As IPAddress() = hostEntry.AddressList   Console.WriteLine(server & " is mapped to")   Dim ipAddress As IPAddress   For each ipAddress In ipAddresses     Console.WriteLine(ipAddress.ToString())   Next Catch e As Exception   Console.WriteLine(e.ToString()) End Try 

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 usually use the first one. The reason for choosing the first one is that a DNS name is often mapped to one IP address only. You can obtain the first IP address mapped to a DNS name using the following code:

 HostEntry.AddressList(0) 

What is more important, once you get an IPAddress object, is that 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. Usually, you need to call the Shutdown method prior to invoking Close to flush all pending data.

Sending and Receiving Streams

After a socket is connected to a remote machine, you can use it to send and receive data. To send data in synchronous mode, you use the Send method. You must place the data you send 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:

 Overloads Public Function Send( ByVal buffer() As Byte ) As Integer 

where buffer is an array of Byte 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:

 Overloads Public Function Send( _   ByVal buffer() As Byte, _   ByVal socketFlags As SocketFlags _ ) As Integer 

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:

 Overloads Public Function Send( _   ByVal buffer() As Byte, _   ByVal size As Integer, _   ByVal socketFlags As SocketFlags _ ) As Integer 

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 to specify an offset position in the buffer to begin sending data. Its signature is as follows:

 Overloads Public Function Send( _   ByVal buffer() As Byte, _   ByVal offset As Integer, _   ByVal size As Integer, _   ByVal socketFlags As SocketFlags _ ) As Integer 

In this overload, offset is the offset position.

To receive data synchronously, you use the Receive method. This method also has four overloads that are similar to the Send method overloads. The signatures of the overloads are as follows:

 Overloads Public Function Receive( ByVal buffer() As Byte ) As Integer Overloads Public Function Receive( _   ByVal buffer() As Byte, _   ByVal socketFlags As SocketFlags _ ) As Integer Overloads Public Function Receive( _   ByVal buffer() As Byte, _   ByVal size As Integer, _   ByVal socketFlags As SocketFlags _ ) As Integer Overloads Public Function Receive( _   ByVal buffer() As Byte, _   ByVal offset As Integer, _   ByVal size As Integer, _   ByVal socketFlags As SocketFlags _ ) As Integer 

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




Real World. NET Applications
Real-World .NET Applications
ISBN: 1590590821
EAN: 2147483647
Year: 2005
Pages: 82

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