יום חמישי, 21 באוקטובר 2010

.net Blocking Socket Server Side

Hi

In this post I will show how create a server using blocking socket in .net.
Reminder:
this implementation uses blocking socket and message that vary in length.

The server side is different from the client side in that it is passive and not active as the client, what that means is that the server reacted to the client i.e. if there is a connection problem and the server can not send an answer to the client it dose not retry ...it waits until the client reconnect and resend to answer.So what the server needs to do is manage it's answers in a way that connection problems will not cause messages to be lost.The server also has an obligation to close half open connections ,half open connection caused by clients that close the connection while the server is blocked on receive.

To manage answers in server you can number the answers in the server and implement a logical acknowledge of messages received by the client.

To handle the half open connection problem you can use time outs...

Now to our example:

First thing we need to open a socket that listens to connection request as so, what you see here the creation of a listening socket and binding it to an IP and port. The value 100 means that 100 clients can request to connect at any given time if 101 will request at the same time 1 will be left out.
 Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, listenport);
            listener.Bind(ipep);
            listener.Listen(100);

After the listening socket is open the server is ready to receive clients, it dose this with the Accept method.Accept() creates a new socket dedicated to the new client with a new port.At first I thought that a firewall will deny the new connection but after testing the code it seams that the code works fine with firewall.
Socket client = listener.Accept();
In order to send and receive using the socket please see my previews post.


This is an Example of a server that collects client IP ....the clients reconnect to the server after a fix period of time, it the client dose not reconnect it is taken of the list.

 public class IpCollector
    {
        #region Private Members
        private Socket listener;
        private Thread Listen;
        private volatile bool _stop;
        private int listenport;
        private Dictionary<string, DateTime> loginTime;
        private System.Timers.Timer CheckForClosedConnections;        
        #endregion

        #region Constructor
        public IpCollector()
        {          
                    
            loginTime = new Dictionary<string, DateTime>();
            CheckForClosedConnections = new System.Timers.Timer(1000 * 60 * 15);//15m
            CheckForClosedConnections.Elapsed += new System.Timers.ElapsedEventHandler(CheckForClosedConnections_Elapsed);
        }
        #endregion

        #region Stop Start
        public void Start(int port)
        {
            listenport = port;
            _stop = false;
            Listen = new Thread(listen);
            Listen.IsBackground = true;
            Listen.Start();
            CheckForClosedConnections.Start();
        }

        public void Stop()
        {
            _stop = true;
            listener.Close();
        }
        #endregion 

        #region Thread Mian Entry Point
        private void listen()
        {
            listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, listenport);
            listener.Bind(ipep);
            listener.Listen(100);

            while (!_stop)
            {
                Socket client = listener.Accept();
                client.ReceiveTimeout = Settings.Default.TCP_SocketTimeOut;
                client.SendTimeout = Settings.Default.TCP_SocketTimeOut;
                IPAddress address = ((IPEndPoint)client.RemoteEndPoint).Address;
                string ipaddress = address.ToString();
                if (ReceiveAck(client))
                {
                    if (SendAck(client))
                    {
                        lock (loginTime)
                        {
                            if (!loginTime.ContainsKey(ipaddress))
                            {                               
                                loginTime.Add(ipaddress, DateTime.Now);
                            }
                            else
                            {
                                loginTime[ipaddress] = DateTime.Now;
                            }
                            
                    }
                }
                CloseConnection(client);
            }
        }
       
        #endregion 

        #region Timer Elapsed
        void CheckForClosedConnections_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            TimeSpan closed = new TimeSpan(Settings.Default.CheckInIntervalInHours, 0, 0);//1h
            DateTime dt = DateTime.Now;
            List<string> closedclients = null;
            lock (loginTime)
            {
                var closedconnections = from lt in loginTime
                                        where dt.Subtract(lt.Value) >= closed
                                        select lt.Key;
                closedclients = closedconnections.ToList();
                foreach (var item in closedclients)
                {                    
                    loginTime.Remove(item);
                }
            }   
        }
        #endregion

        #region Public Method
        public List<string> GetClients()
        {
            lock (loginTime)
            {
                return loginTime.Keys.ToList();
            }
        }
        #endregion

        #region TCP Help
        private bool SendAck(Socket s)
        {
            try
            {
                byte[] ack = BitConverter.GetBytes(true);
                int total, size, dataleft, sent;
                ack = ByteArrayHelper.CancatByteArray(BitConverter.GetBytes(ack.Length), ack);
                total = 0;
                size = ack.Length;
                dataleft = size;
                while (total < size)//send the object
                {
                    sent = s.Send(ack, total, dataleft, SocketFlags.None);
                    total += sent;
                    dataleft -= sent;
                }
                return true; 
            }
            catch (Exception ex)
            {                
                return false;
            }
        }

        private bool ReceiveAck(Socket s)
        {
            try
            {                
                int total = 0;
                int recv = 0;
                int size = 0;
                byte[] datasize = new byte[4];
                while ((recv = s.Receive(datasize, 0, 4, 0)) < 4)
                {
                    if (recv == 0)
                    {//problem           
                        return false;
                    }
                    recv += s.Receive(datasize, 0, 4, 0);
                }
                size = BitConverter.ToInt32(datasize, 0);
                if (size == 1)
                {
                    int dataleft = size;
                    byte[] data = new byte[size];
                    while (total < size)
                    {
                        if (recv == 0)
                        {//problem                     
                            return false;
                        }
                        recv = s.Receive(data, total, dataleft, SocketFlags.None);
                        total += recv;
                        dataleft -= recv;
                    }
                    return BitConverter.ToBoolean(data, 0) == true;
                }                             
                return false;
            }
            catch (Exception ex)
            {                
                return false;
            }
        }

        private void CloseConnection(Socket s)
        {
            try
            {
                s.Shutdown(SocketShutdown.Both);
            }
            catch
            {

            }
            s.Close();
        }
        #endregion
    }

Thats all for new....

        



.net Blocking Socket

Hi

In this post I will show how to use blocking socket in .net.

First thing is first what is blocking socket?

Well socket is one way to send byte array through the net ,blocking means that while the send/receive operation is taking place the thread is blocked until time out expires.

In this post I will focus on the client side (on the server side there is a listening socket).
In this example the client sends and receive byte arrays that are not fix in size ,that means that the client needs to calculate the length of the incoming byte array.To do this the client and server have an agreement that the first 4 byte in the array represent the length of the message, that means that the client while receiving a message reads the first 4 bytes converts them to an integer and reads the reset of the message.When the client sends a message it adds the length of the byte array as a prefix before sending it to the server.

In this post you can see that the client handles connection problems and can reconnect when needed.
It is important that the client will recognize that it needs to recontact to the server.To do this I used socket time out ,when sending the socket tells if there is a connection problem so this is easy to handle but when receiving the socket is not aware to connection problems and is in blocking mode so I used time outs to get around this predicament.It is important to know that when time out expires the socket can not be reused so the it needs to reconnect.

Code Example:
public class ClientReceiver
    {

        private Thread receiver;
        private IPEndPoint ipep;
        private Socket server;
        private int sessions, interval;

        public ClientReceiver()
        {

        }

        public void Start(IPAddress ip, int port, int sessions, int interval)
        {
            this.sessions = sessions;
            this.interval = interval;
            ipep = new IPEndPoint(ip, port);
            receiver = new Thread(Do);
            receiver.IsBackground = true;
            receiver.Start();
        }

        private void Do()
        {          
            for (int k = 0; k < sessions; k++)
            {
                Socket service = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                service.Connect(ipep);
                Console.WriteLine("Connecting.....");
                if (service.Connected)
                {
                    byte[] receiveddata;
                    int j = 0;
                    try
                    {
                        if (SendAck(service))
                        {
                            while (j < interval)
                            {                           
                                if (Receive(service, out receiveddata))
                                {
                                    Console.WriteLine(string.Format("Received: {0} in session {1}", j, k));
                                    j++;
                                }
                            }

                        }   
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
                Console.WriteLine("Disconnecting......");
                CloseConnection(service);  

            }

        }

        private void CloseConnection(Socket s)
        {
            try
            {
                s.Shutdown(SocketShutdown.Both);
            }
            catch 
            {               
               
            }
            s.Close();
        }


        private bool Receive(Socket s, out byte[] DataReceived)
        {
            int total = 0;
            int recv = 0;
            int size = 0;
            byte[] datasize = new byte[4];
            try
            {
                while ((recv = s.Receive(datasize, 0, 4, 0)) < 4)
                {
                    if (recv == 0)
                    {//problem                            
                        DataReceived = null;
                        return false;
                    }
                    recv += s.Receive(datasize, 0, 4, 0);
                }
                size = BitConverter.ToInt32(datasize, 0);
                int dataleft = size;
                byte[] data = new byte[size];
                while (total < size)
                {
                    if (recv == 0)
                    {//problem                            
                        DataReceived = null;
                        return false;
                    }
                    recv = s.Receive(data, total, dataleft, SocketFlags.None);
                    total += recv;
                    dataleft -= recv;
                }
                DataReceived = data;
                return SendAck(s);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                DataReceived = null;
                return false;
            }

        }

        public bool SendAck(Socket s)
        {
            byte[] datasize = new byte[4];
            byte[] data = BitConverter.GetBytes(0);
            int total, size, dataleft, sent;
            try
            {
                total = 0;
                size = data.Length;
                dataleft = size;
                datasize = BitConverter.GetBytes(size);
                sent = s.Send(datasize);//send size of object                
                while (total < size)//send the object
                {
                    sent = s.Send(data, total, dataleft, SocketFlags.None);
                    total += sent;
                    dataleft -= sent;
                }
                return true;

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;

            }
        }
    }

WPF Blinking Performance problem

Dooring our development I came a cross an interesting problem regarding performance with wpf story board. I developed an application that has some blinking/flashing user controls , I implemented that behavior with a binding to a property that starts a story board which tells the control's background color to go form whit to red. you can see in the example how to flashing is implemented.

    <DataTrigger Value="True" Binding="{Binding FlashMe, Mode=OneWay}" >
                    <DataTrigger.EnterActions>
                        <BeginStoryboard  x:Name="beginirrgular" >
                            <BeginStoryboard.Storyboard>
                                <Storyboard >
                                    <ColorAnimation Storyboard.TargetProperty="Background.Color" FillBehavior="Stop" RepeatBehavior="Forever"  From="Red" To="White" Duration="0:0:1" />
                                </Storyboard>
                            </BeginStoryboard.Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions >
                        <StopStoryboard  BeginStoryboardName="beginirrgular"/>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
   
When I ran the application I saw that the CPU usage is around 20 in the task manager ,I believe that this causes a major performance problem.

To solve this problem I tried some several different ways the one that worked is what I will show in this post.

I used a converter and a timer thread that changes a boolean property to change the background color, the effect GUI wise is the same and performance wise the CPU usage was much lower than before.

This is the Code:
bool _myflash = false;
        System.Timers.Timer _mytimer;

        public bool Myflash
        {
            get { return _myflash; }
            set 
            {
                _myflash = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Myflash"));
            }
        }

        public MainWindow()
        {            
            _mytimer = new System.Timers.Timer(500);
            _mytimer.Elapsed += new System.Timers.ElapsedEventHandler(_mytimer_Elapsed);
            this.DataContext = this;
            InitializeComponent();
        }

        void foo()
        {            
            Myflash = !Myflash;
        }

        void _mytimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Action method = foo;
            dis.BeginInvoke(method);
        }
As you can see there is a timer that fries the elapsed event and changes the bool MyFlash using dispatcher.

This is the converter that switches the color back and forth,

public class ConvertMe : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null)
            {
                bool val = System.Convert.ToBoolean(value);
                if (val)
                {
                    return new SolidColorBrush(Colors.Red);
                }
                else
                {
                    return new SolidColorBrush(Colors.Transparent);
                }
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
Using simple binding to the converter and the property MyFlash we are done.

<Button Content="Start Blinking" Click="Button_Click" Background="{Binding Myflash,Converter={StaticResource MeConvetor}}"/>
All you need is to start the timer thread .....:)