Socket Programming with the .NET Compact Framework


The central class for socket programming with the .NET Compact Framework is the System.Net.Sockets.Socket class. The procedure for getting a Socket class connected to a remote computer depends on whether the socket connects as the host or as the client. Once the Socket is connected to a remote computer, however, the processes for reading and writing are exactly the same.

Making a Connection as a Client

To successfully make a connection as a client, we must first understand the System.Net.EndPoint class. The EndPoint holds the information about where to connect to the IPv4 address of the host and the desired port. To set up a valid EndPoint and use it to connect a socket to a host, follow these steps:

  1. Declare a variable for an EndPoint and a Socket.

  2. Instantiate the EndPoint by passing the address and port number information into the constructor. There are two common ways to do this, depending on whether you know the address of the host, such as 172.68.25.34 , or only the DNS name of the host, such as www.mycomputer.net .

    FINDING THE IP ADDRESS OF THE HOST

    If you know the IP address of the host, use the IPAddress in the constructor. For example, this line of code instantiates a new EndPoint that describes the host at IP address 172.68.25.34 , port 9981:

     
     C# EndPoint l_EndPoint = new IPEndPoint( IPAddress.Parse(         ) "172.68.25.34", Convert.ToInt16(9981)); VB Dim l_EndPoint As System.Net.EndPoint l_EndPoint = New         System.Net.IPEndPoint(System.Net.IPAddress.         Parse("172.68.25.34"), System.Int32.Parse(Me.txtPort.Text)) 

    If you don't know the IP address of the host, then you must use DNS lookup to match the name of the host with its actual IP address. DNS lookup returns the IP address associated with a name. The code to do the lookup in a very simple case looks like this:

     
     C# IPHostEntry l_IPHostEntry = Dns.Resolve("www.mycomputer.net"); EndPoint l_EndPoint = new IPEndpoint(l_IPHostEntry.AddressList[0],         9981); VB Dim l_IPHostEntry As System.Net.IPHostEntry l_IPHostEntry = System.Net.Dns.Resolve("www.mycomputer.net") l_EndPoint = New System.Net.IPEndPoint(l_IPHostEntry.         AddressList(0), 9981) 

  3. Use the EndPoint to attempt to connect the socket to the host. Be sure to use a try/catch clause here because the attempt will throw an exception if there is a problem, such as the host's refusing to accept the connection.

The following code sample illustrates the three steps just described:

 
 C# try {     Socket l_Socket = new Socket(Socket(AddressFamily.InterNetwork,             SocketType.Stream, ProtocolType.Tcp);     l_Socket.Connect(l_EndPoint);     if (l_Socket.Connected){        // l_Socket is now ready to send and receive data     } } catch (SocketException e) { /* do something about it */ } VB Dim l_Socket As System.Net.Sockets.Socket Try     l_Socket = New System.Net.Sockets.Socket(             System.Net.Sockets.AddressFamily.InterNetwork,             System.Net.Sockets.SocketType.Stream,             System.Net.Sockets.ProtocolType.Tcp)     l_Socket.Connect(l_EndPoint)     If (l_Socket.Connected) Then       ' l_Socket is now ready to send and receive data     End If Catch e as System.Net.Sockets.SocketException     ' Do something about the problem End Try 

Receiving a Connection as a Host

You can acquire a socket connection to a remote computer by acting as the host. When a device acts as a host, it waits to receive a connection from another client. For your device to receive a connection as a host, you must set up a socket to listen on a specific port until someone sends a request to connect with your device. Follow these steps to listen on a socket for clients to connect to you:

  1. Create a new socket that listens for new connections.

  2. Bind the listening socket to a specific port so that it listens for connections on only that port.

  3. Call Accept() on the listening socket to derive another socket when someone connects to you. Your code can read and write to the deriving socket, and the listening socket continues to wait for new connections.

The following code sample illustrates the three steps just described:

 
 C# m_listenSocket = new Socket(AddressFamily.InterNetwork,         SocketType.Stream, ProtocolType.Tcp); m_listenSocket.Bind(new IPEndPoint(IPAddress.Any, 8758)); m_listenSocket.Listen((int)SocketOptionName.MaxConnections); m_connectedSocket = m_listenSocket.Accept(); if (m_connectedSocket != null) {     if (m_connectedSocket.Connected)     {        // Someone has connected to us.     }  } VB m_listenSocket = new Socket(AddressFamily.InterNetwork,         SocketType.Stream, ProtocolType.Tcp) m_listenSocket.Bind(new IPEndPoint(IPAddress.Any, 8758)) m_listenSocket.Listen((int)SocketOptionName.MaxConnections) m_connectedSocket = m_listenSocket.Accept() If (m_connectedSocket != null) Then     If (m_connectedSocket.Connected) Then        ' Someone has connected to us.     End If End If 

Reading and Writing with a Connected Socket

Once a socket is connected to a remote computer, it can be used to send and receive data. The simplest way to do this is to call Socket.Send() to send data and Socket.Receive() to receive data.

Writing Data to a Socket with Socket.Send

Socket.Send() has four overloads, each offering a different level of control over what is sent:

Send(Byte[] buffer) This overload sends everything inside the buffer byte array.

Send(Byte[] buffer, SocketFlags socketFlags) This overload sends everything in buffer with special control over how the data is routed.

Send(Byte[] buffer, Int32 size, SocketFlags socketFlags) This overload sends everything in the buffer up to size bytes. If you want to send only part of a buffer, then you can specify SocketFlags.None to use the default routing behavior. For example, to send the first 16 bytes out of a byte array, you could use l_Socket.Send(l_buffer, 16, SocketFlags.None) .

Send(Byte[] buffer, Int32 offset Int32 size, SocketFlags socketFlags) This overload is like the previous one except you can specify which index within the byte array to start from. For example, to send bytes 3 through 7 of a byte array, you could use the following:

 
 C# l_Socket.Send(l_buffer, 2, 6, SocketFlags.None); VB l_Socket.Send(l_buffer, 3, 7, SocketFlags.None) 

The Send method returns the number of bytes successfully sent. The problem with the Send() method is that it seems like a lot of work to convert everything you want to send into an array of bytes just to send it through a socket. Fortunately, the .NET Compact Framework supports two very useful classes, System.Text.Encoding and System.Convert , that make it easy to convert fundamental data types into byte arrays that can be sent through the socket. To send an entire object through a socket, you must serialize the object, as discussed in the section "Serializing Objects for Transmission through a Socket."

The easiest way to understand how to use the Encoding and Convert classes is to look at examples. The following examples assume that a socket named l_Socket exists and is connected:

 
 C# 
  • Send a string by using ASCII byte encoding:

     
     l_Socket.Send(Encoding.ASCII.GetBytes("Send me") 
  • Send a string by using Unicode byte encoding:

     
     l_Socket.Send(Encoding.Unicode.GetBytes("Send me") 
  • Send the integer value 2003 as plain ASCII text:

     
     l_Socket.Send(Encoding.ASCII.GetBytes(Convert.ToString(2003)) 
  • Send the floating-point value 2.71 as plain ASCII text:

     
     l_Socket.Send(Encoding.ASCII.GetBytes(Convert.ToString(2.71)) VB 
  • Send a string by using ASCII byte encoding:

     
     l_Socket.Send(System.Text.Encoding.ASCII.GetBytes("Send me") 
  • Send a string by using Unicode byte encoding:

     
     l_Socket.Send(System.Text.Encoding.Unicode.GetBytes("Send me") 
  • Send the integer value 2003 as plain ASCII text:

     
     l_Socket.Send(System.Text.Encoding.ASCII.GetBytes(         Convert.ToString(2003)) 
  • Send the floating-point value 2.71 as plain ASCII text:

     
     l_Socket.Send(System.Text.Encoding.ASCII.GetBytes(         Convert.ToString(2.71)) 
Reading Data from a Socket with Socket.Receive

Receive data from a socket through the Socket.Receive method. Receive has four overloads, similar to the overloads for Socket.Send . Each of the following overloads returns the number of bytes successfully read:

Receive (Byte[] buffer ) This overload receives data into buffer.

Receive (Byte[] buffer, SocketFlags socketFlags) This overload receives data into buffer by using the flags to specify controlling how data is routed.

Receive (Byte[] buffer, Int32 size, SocketFlags socketFlags) This overload receives up to size bytes of data into the buffer. Even if more data is available, it is ignored. You can retrieve the remaining data by calling Receive again. If you want to receive only a specified number of bytes but you have no restrictions on the routing behavior, then you can specify SocketFlags.None to use the default routing behavior. For example, to receive only the first the 16 bytes of the available data, use l_Socket.Receive(l_buffer, 16, SocketFlags.None)

Receive (Byte[] buffer, Int32 offset Int32 size, SocketFlags socketFlags) This overload is like the previous one except you can specify which index within the byte array to use to start writing data into the array. For example, to receive up to 7 bytes of data into the buffer starting at position 3 in the buffer, use this code:

 
 C# l_Socket.Receive(l_buffer, 2, 6, SocketFlags.None); VB l_Socket.Receive(l_buffer, 3, 7, SocketFlags.None) 

TRANSMITTING BINARY REPRESENTATION OF DATA

It is possible to write code that sends the byte-wise representation of numerical values instead of converting them to strings or converting them to network-ordered representations. This is a dangerous habit to get into, because different platforms have different internal representations for fundamental data types. If you are writing an application that transmits fundamental data types and the other party might not be a .NET application, then the bytes you send representing numerical values might be invalid to the remote party.


Just as there are techniques for converting the data to send out of a socket into byte arrays, there are simple techniques for converting byte arrays into fundamental data types. As before, the Encoding and Convert classes provide the means for conversion, and we will look at examples. These examples assume the data has been received into a Byte array named l_Buffer :

 
 C# 
  • Convert received bytes into an ASCII string:

     
     string l_ASCII = Encoding.ASCII.GetString(l_Buffer); 
  • Convert received bytes into a Unicode string:

     
     string l_ASCII = Encoding.Unicode.GetString(l_Buffer); 
  • Convert the received bytes, which hold an encoded ASCII text integer, into a 32-bit-wide integer:

     
     int l_Integer = Convert.ToInt32(Encoding.ASCII.GetString(l_Buffer)); 
  • Convert the received bytes, which hold an encoded ASCII text integer, into a Double:

     
     Double l_Double = Convert.ToInt32(Encoding.ASCII.GetString(l_Double)); VB 
  • Convert received bytes into an ASCII string:

     
     Dim l_ASCII as string l_ASCII = Encoding.ASCII.GetString(l_Buffer) 
  • Convert received bytes into a Unicode string:

     
     Dim l_ASCII as string string l_ASCII = Encoding.Unicode.GetString(l_Buffer) 
  • Convert the received bytes, which hold an encoded ASCII text integer, into a 32-bit-wide integer:

     
     Dim l_Integer as Integer l_Integer = Convert.ToInt32(Encoding.ASCII.GetString(l_Buffer)) 
  • Convert the received bytes, which hold an encoded ASCII text integer, into a Double:

     
     Dim l_Double as Double l_Double = Convert.ToInt32(Encoding.ASCII.GetString(l_Double)) 

Table 5.1 lists all of the conversions supported by the Convert class on the .NET Compact Framework.

ILLEGAL CONVERSIONS

Although there are many conversions available, exceptions are thrown for conversions that are illegal. For example, trying to convert a large long to a short will cause an OverFlowException .


Table 5.1. The Convert Class on the .NET Compact Framework

METHOD

NAME ACCEPTS THESE INPUT TYPES

ToBoolean

object, bool, sbyte, char, byte, short, ushort, int, uint, long, String, float, double, decimal

ToChar

object, char, sbyte, byte, short, ushort, int, uint, long, ulong, String, float, double, decimal

ToSByte

object, bool, sbyte, char, byte, short, ushort, int, uint, long, ulong, float, double, decimal, String

ToByte

object, bool, byte, char, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal, String

ToInt16

object, bool, char, sbyte, byte, ushort, int, uint, short, long, ulong, float, double, decimal, String

ToUInt16

object, bool, char, sbyte, byte, short, int, ushort, uint, long, ulong, float, double, decimal, String

ToInt32

object, bool, char, sbyte, byte, short, ushort, uint, int, long, ulong, float, double, decimal, String

ToUInt32

object, bool, char, sbyte, byte, short, ushort, int, uint, long, ulong, float, double, decimal, String

ToInt64

object, bool, char, sbyte, byte, short, ushort, int, uint, ulong, long, float, double, decimal, String

ToUInt64

object, bool, char, sbyte, byte, short, ushort, int, uint, long, UInt64, float, double, decimal, String

ToSingle

object, sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, String, bool

ToDouble

object, sbyte, byte, short, char, ushort, int, uint, long, ulong, float, double, decimal, String, bool

ToDecimal

object, sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, String, decimal, bool, DateTime

ToDateTime

object, String

ToString

Object, bool, char, sbyte, byte, short, ushort, int, uint, long, ulong, float, double, decimal, Decimal, DateTime

ToBase64String

byte[]

byte[]FromBase64String

String

ToBase64CharArray

byte[]

byte[]FromInt64CharArray

char[]

Sample Application: Remote Hello

This sample application pulls together the three most basic actions developers do with sockets: connect to a host, listen for a client, and exchange data. The application is split into two separate programs, a server and a client. The server always listens on port 8758 and uses DNS lookup to show what its IP address is. The client has a space for entering an IP address and a button to connect to the remote host.

When a connection is made, the server sends a string that says "Hello!" and the client displays it. Then the client closes the connection, and the host starts listening again.

The C# version of the Remote Hello client is in the directory SampleApplications\ Chapter5\RemoteHelloClient_CSharp , and the VB version is in SampleApplications\ Chapter5\RemoteHelloClient_VB . The server is in the folders RemoteHelloServer_CSharp and RemoteHelloServer_VB .

Observe that the code accesses the same classes from the .NET Compact Framework regardless of which language is used. Also, because sockets are platform agnostic , you can connect to the Visual Basic host with the C# client and vice versa.



Microsoft.NET Compact Framework Kick Start
Microsoft .NET Compact Framework Kick Start
ISBN: 0672325705
EAN: 2147483647
Year: 2003
Pages: 206

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