Click here to Skip to main content
Click here to Skip to main content

An Introduction to Socket Programming in .NET using C#

, 10 Jun 2005
Rate this:
Please Sign up or sign in to vote.
In this article, we will learn the basics of socket programming in .NET Framework using C#. Secondly, we will create a small application consisting of a server and a client which will communicate using TCP and UDP protocols.

Introduction

In this article, we will learn the basics of socket programming in .NET Framework using C#. Secondly, we will create a small application consisting of a server and a client, which will communicate using TCP and UDP protocols.

Pre-requisites

  • Must be familiar with .NET Framework.
  • Should have good knowledge of C#.
  • Basic knowledge of socket programming.

1.1 Networking basics:

Inter-Process Communication i.e. the capability of two or more physically connected machines to exchange data, plays a very important role in enterprise software development. TCP/IP is the most common standard adopted for such communication. Under TCP/IP each machine is identified by a unique 4 byte integer referred to as its IP address (usually formatted as 192.168.0.101). For easy remembrance, this IP address is mostly bound to a user-friendly host name. The program below (showip.cs) uses the System.Net.Dns class to display the IP address of the machine whose name is passed in the first command-line argument. In the absence of command-line arguments, it displays the name and IP address of the local machine.

using System;
using System.Net;
class ShowIP{
    public static void Main(string[] args){
        string name = (args.Length < 1) ? Dns.GetHostName() : args[0];
        try{
            IPAddress[] addrs = Dns.Resolve(name).AddressList;
            foreach(IPAddress addr in addrs) 
                Console.WriteLine("{0}/{1}",name,addr);
        }catch(Exception e){
            Console.WriteLine(e.Message);
        }
    }
}

Dns.GetHostName() returns the name of the local machine and Dns.Resolve() returns IPHostEntry for a machine with a given name, the AddressList property of which returns the IPAdresses of the machine. The Resolve method will cause an exception if the mentioned host is not found.

Though IPAddress allows to identify machines in the network, each machine may host multiple applications which use network for data exchange. Under TCP/IP, each network oriented application binds itself to a unique 2 byte integer referred to as its port-number which identifies this application on the machine it is executing. The data transfer takes place in the form of byte bundles called IP Packets or Datagrams. The size of each datagram is 64 KByte and it contains the data to be transferred, the actual size of the data, IP addresses and port-numbers of sender and the prospective receiver. Once a datagram is placed on a network by a machine, it will be received physically by all the other machines but will be accepted only by that machine whose IP address matches with the receiver’s IP address in the packet. Later on, this machine will transfer the packet to an application running on it which is bound to the receiver’s port-number present in the packet.

TCP/IP suite actually offers two different protocols for data exchange. The Transmission Control Protocol (TCP) is a reliable connection oriented protocol while the User Datagram Protocol (UDP) is not very reliable (but fast) connectionless protocol.

1.2 Client-Server programming with TCP/IP:

Under TCP there is a clear distinction between the server process and the client process. The server process starts on a well known port (which the clients are aware of) and listens for incoming connection requests. The client process starts on any port and issues a connection request.

The basic steps to create a TCP/IP server are as follows:

  1. Create a System.Net.Sockets.TcpListener with a given local port and start it:
    TcpListener listener = new TcpListener(local_port);
    listener.Start();
  2. Wait for the incoming connection request and accept a System.Net.Sockets.Socket object from the listener whenever the request appears:
    Socket soc = listener.AcceptSocket(); // blocks
  3. Create a System.Net.Sockets.NetworkStream from the above Socket:
    Stream s = new NetworkStream(soc);
  4. Communicate with the client using the predefined protocol (well established rules for data exchange):
  5. Close the Stream:
    s.Close();
  6. Close the Socket:
    s.Close();
  7. Go to Step 2.

Note when one request is accepted through step 2 no other request will be accepted until the code reaches step 7. (Requests will be placed in a queue or backlog.) In order to accept and service more than one client concurrently, steps 2 – 7 must be executed in multiple threads. Program below (emptcpserver.cs) is a multithreaded TCP/IP server which accepts employee name from its client and sends back the job of the employee. The client terminates the session by sending a blank line for the employee’s name. The employee data is retrieved from the application’s configuration file (an XML file in the directory of the application and whose name is the name of the application with a .config extension).

using System;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Configuration;

class EmployeeTCPServer{
    static TcpListener listener;
    const int LIMIT = 5; //5 concurrent clients
    
    public static void Main(){
        listener = new TcpListener(2055);
        listener.Start();
        #if LOG
            Console.WriteLine("Server mounted, 
                            listening to port 2055");
        #endif
        for(int i = 0;i < LIMIT;i++){
            Thread t = new Thread(new ThreadStart(Service));
            t.Start();
        }
    }
    public static void Service(){
        while(true){
            Socket soc = listener.AcceptSocket();
            //soc.SetSocketOption(SocketOptionLevel.Socket,
            //        SocketOptionName.ReceiveTimeout,10000);
            #if LOG
                Console.WriteLine("Connected: {0}", 
                                         soc.RemoteEndPoint);
            #endif
            try{
                Stream s = new NetworkStream(soc); 
                StreamReader sr = new StreamReader(s);
                StreamWriter sw = new StreamWriter(s);
                sw.AutoFlush = true; // enable automatic flushing
                sw.WriteLine("{0} Employees available", 
                      ConfigurationSettings.AppSettings.Count);
                while(true){
                    string name = sr.ReadLine();
                    if(name == "" || name == null) break;
                    string job = 
                        ConfigurationSettings.AppSettings[name];
                    if(job == null) job = "No such employee";
                    sw.WriteLine(job);
                }
                s.Close();
            }catch(Exception e){
                #if LOG
                    Console.WriteLine(e.Message);
                #endif
            }
            #if LOG
                Console.WriteLine("Disconnected: {0}", 
                                        soc.RemoteEndPoint);
            #endif
            soc.Close();
        }
    }
}

Here is the content of the configuration file (emptcpserver.exe.config) for the above application:

<configuration>
    <appSettings>
        <add key = "john" value="manager"/> 
        <add key = "jane" value="steno"/>
        <add key = "jim" value="clerk"/>
        <add key = "jack" value="salesman"/>
    </appSettings>
</configuration>

The code between #if LOG and #endif will be added by the compiler only if the symbol LOG is defined during compilation (conditional compilation). You can compile the above program either by defining the LOG symbol (information is logged on the screen):

  • csc /D:LOG emptcpserver.cs

or without the LOG symbol (silent mode):

  • csc emptcpserver.cs

Mount the server using the command start emptcpserver.

To test the server you can use: telnet localhost 2055.

Or, we can create a client program. Basic steps for creating a TCP/IP client are as follows:

  1. Create a System.Net.Sockets.TcpClient using the server’s host name and port:
    TcpClient client = new TcpClient(host, port);
  2. Obtain the stream from the above TCPClient.
    Stream s = client.GetStream()
  3. Communicate with the server using the predefined protocol.
  4. Close the Stream:
    s.Close();
  5. Close the connection:
    client.Close();

The program below (emptcpclient.cs) communicates with EmployeeTCPServer:

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

class EmployeeTCPClient{
    public static void Main(string[] args){
        TcpClient client = new TcpClient(args[0],2055);
        try{
            Stream s = client.GetStream();
            StreamReader sr = new StreamReader(s);
            StreamWriter sw = new StreamWriter(s);
            sw.AutoFlush = true;
            Console.WriteLine(sr.ReadLine());
            while(true){
                Console.Write("Name: ");
                string name = Console.ReadLine();
                sw.WriteLine(name);
                if(name == "") break;
                Console.WriteLine(sr.ReadLine());
            }
            s.Close();
        }finally{
            // code in finally block is guranteed 
            // to execute irrespective of 
            // whether any exception occurs or does 
            // not occur in the try block
            client.Close();
        } 
    }
}

1.3 Multicasting with UDP

Unlike TCP, UDP is connectionless i.e. data can be send to multiple receivers using a single socket. Basic UDP operations are as follows:

  1. Create a System.Net.Sockets.UdpClient either using a local port or remote host and remote port:
    UdpClient client = new UdpClient(local_ port);

    or

    UdpClient client = new UdpClient(remote_host, remote_port);
  2. Receive data using the above UdpClient:
    System.Net.IPEndPoint ep = null;
    byte[] data = client.Receive(ref ep);

    byte array data will contain the data that was received and ep will contain the address of the sender.

  3. Send data using the above UdpClient..

    If the remote host name and the port number have already been passed to the UdpClient through its constructor, then send byte array data using:

    client.Send(data, data.Length);

    Otherwise, send byte array data using IPEndPoint ep of the receiver:

    client.Send(data, data.Length, ep);

The program below (empudpserver.cs) receives the name of an employee from a remote client and sends it back the job of that employee using UDP:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Configuration;

class EmployeeUDPServer{
    public static void Main(){
        UdpClient udpc = new UdpClient(2055);
        Console.WriteLine("Server started, servicing on port 2055");
        IPEndPoint ep = null;
        while(true){
            byte[] rdata = udpc.Receive(ref ep);
            string name = Encoding.ASCII.GetString(rdata);
            string job = ConfigurationSettings.AppSettings[name];
            if(job == null) job = "No such employee";
            byte[] sdata = Encoding.ASCII.GetBytes(job);
            udpc.Send(sdata,sdata.Length,ep);
        }
    }
}

Here is the content of the configuration file (empudpserver.exe.config) for above application:

<configuration>
    <appSettings>
        <add key = "john" value="manager"/> 
        <add key = "jane" value="steno"/>
        <add key = "jim" value="clerk"/>
        <add key = "jack" value="salesman"/>
    </appSettings>
</configuration>

The next program (empudpclient.cs) is a UDP client to the above server program:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class EmployeeUDPClient{
    public static void Main(string[] args){
        UdpClient udpc = new UdpClient(args[0],2055);
        IPEndPoint ep = null;
        while(true){
            Console.Write("Name: ");
            string name = Console.ReadLine();
            if(name == "") break;
            byte[] sdata = Encoding.ASCII.GetBytes(name);
            udpc.Send(sdata,sdata.Length);
            byte[] rdata = udpc.Receive(ref ep);
            string job = Encoding.ASCII.GetString(rdata);
            Console.WriteLine(job);
        }
    }
}

UDP also supports multicasting i.e. sending a single datagram to multiple receivers. To do so, the sender sends a packet to an IP address in the range 224.0.0.1 – 239.255.255.255 (Class D address group). Multiple receivers can join the group of this address and receive the packet. The program below (stockpricemulticaster.cs) sends a datagram every 5 seconds containing the share price (a randomly calculated value) of an imaginary company to address 230.0.0.1:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class StockPriceMulticaster{
    static string[] symbols = {"ABCD","EFGH", "IJKL", "MNOP"};
    public static void Main(){
        UdpClient publisher = new UdpClient("230.0.0.1",8899);
        Console.WriteLine("Publishing stock prices to 230.0.0.1:8899");
        Random gen = new Random();
        while(true){
            int i = gen.Next(0,symbols.Length);
            double price = 400*gen.NextDouble()+100;
            string msg = String.Format("{0} {1:#.00}",symbols,price);
            byte[] sdata = Encoding.ASCII.GetBytes(msg);
            publisher.Send(sdata,sdata.Length);
            System.Threading.Thread.Sleep(5000);
        }
    }
}

Compile and start stockpricemulticaster.

The next program (stockpricereceiver.cs) joins the group of address 230.0.0.1, receives 10 stock prices and then leaves the group:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class StockPriceReceiver{
    public static void Main(){
        UdpClient subscriber = new UdpClient(8899);
        IPAddress addr = IPAddress.Parse("230.0.0.1");
        subscriber.JoinMulticastGroup(addr);
        IPEndPoint ep = null;
        for(int i=0; i<10;i++){
            byte[] pdata = subscriber.Receive(ref ep);
            string price = Encoding.ASCII.GetString(pdata);
            Console.WriteLine(price);
        }
        subscriber.DropMulticastGroup(addr);
    }
}

Compile and run stockpricereceiver.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

.NETian
Software Developer (Senior) Buyagift Limited.
United Kingdom United Kingdom
Having completed my Bsc(Hons) in Computing from Staffordshire University U.K and Masters in Software Development and Security from Birmingham City University. I am now working as a Senior Software Engineer at Buyagift Limited - UK.
 
Mubashir Afroz.
Buyagift Ltd.
www.buyagift.co.uk
---------------------

Comments and Discussions

 
QuestionThankyou! PinmemberMember 104531155-Mar-14 22:27 
GeneralEasy to Understand for any programming level Pinmemberglaphanking24-Feb-14 13:31 
GeneralMy vote of 5 PinmemberM Rayhan22-Jan-14 22:47 
GeneralRe: My vote of 5 Pinmemberbalmerhevi26-Jan-14 20:14 
QuestionGreat PinmemberJohn Mike H.21-Aug-13 15:28 
GeneralMy vote of 5 Pinmembernsraja2-Aug-13 8:08 
Questions.close repeated twice PinmemberTailGunCharlie30-Jul-13 23:41 
GeneralMy vote of 5 Pinmemberhebsiboy29-Apr-13 1:47 
GeneralMy vote of 5 Pinmembersuramrit7-Feb-13 0:58 
Questioncommunication between 2 host with Private IPs, on differnt networks Pinmemberneelu777923-Oct-12 22:59 
AnswerRe: communication between 2 host with Private IPs, on differnt networks PinmemberJeppe M H4-Dec-12 20:36 
GeneralMy vote of 4 Pinmemberjashanprt10-Oct-12 16:38 
GeneralMy vote of 5 [modified] Pinmemberhari1911310-Aug-12 7:13 
QuestionThanks PinmemberMember 794342018-Jun-12 0:51 
Questionlistening reserve port Pinmemberonlybj8-Feb-12 6:36 
QuestionChat Application without server/client relation PinmemberMember 781598522-Sep-11 20:26 
QuestionTCPclient with 18 connections its possible? PinmemberDenis99994-Jul-11 21:47 
GeneralMy vote of 4 Pinmemberdisha7027-Jan-11 21:58 
GeneralMy vote of 5 PinmemberMember 160430015-Dec-10 0:11 
GeneralMy vote of 3 PinmemberDebashis Chowdhury (CUET)23-Nov-10 21:53 
GeneralMy vote of 5 PinmemberDavid Pérez Marinas27-Oct-10 23:25 
GeneralMy vote of 5 Pinmemberpariyoo2-Aug-10 19:40 
GeneralVery nice article and simple to understand Pinmemberthompsons5-Dec-09 9:41 
QuestionWhat about peer to peer connection PinmembermatiIsGreat19-Aug-09 0:55 
Generalexcellent article PinmemberMember 333548910-Jul-09 0:32 
GeneralCorrection PinmemberXmen W.K.17-Apr-09 14:54 
General[Message Deleted] Pinmemberit.ragester2-Apr-09 21:47 
GeneralExcellent PinmemberRajkumar Aili9-Jul-08 1:46 
Generalclient connection status check Pinmemberankita luniya17-Mar-08 2:05 
GeneralClosing client question PinmemberY_R10-Dec-07 21:48 
GeneralBuen articulo PinmemberNoel Ricardo13-Jul-07 13:58 
GeneralNice article PinmemberHarish Iyer21-Jun-07 0:03 
GeneralRe: Nice article Pinmember.NETian21-Jun-07 0:56 
GeneralTwo Port communication PinmemberSakthiSurya8-Feb-07 2:59 
GeneralRe: Another lib Pinmember.NETian11-Jul-06 3:09 
GeneralGood Article and Simple PinmemberRefky Wahib25-May-06 0:40 
GeneralRe: Good Article and Simple Pinmember.NETian25-May-06 3:51 
GeneralGood article PinmemberShane Story31-Mar-06 7:34 
Generalother way (... better way ??) Pinmembersbouli25-Jul-05 0:26 
GeneralRe: other way (... better way ??) Pinmember.NETian25-Jul-05 7:25 
GeneralReferences on Socket Programming PinmembervSoares13-Jun-05 0:51 
GeneralRe: References on Socket Programming PinmemberMubashir Afroz13-Jun-05 6:22 
GeneralYou need to sort the formatting PinmemberGiles11-Jun-05 1:12 
GeneralRe: You need to sort the formatting PinsussAnonymous12-Jun-05 9:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140814.1 | Last Updated 11 Jun 2005
Article Copyright 2005 by .NETian
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid