Racing condition support added

Jun 6, 2012 at 1:22 PM

I've recently improved this framework in order to support racing condition when several timers wake up at the same time to send socket messages. The current implementation does not support this scenario causing a deserialization issue client-side. The implementation below supports also this scenario. Feel free to share:

        private void OnSocketReceive(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred == 0)
            {
                this.OnConnectionLost();
                this.socket.Close();
                //reconnect if possible
                if (dispatcher != null)
                    this.Reconnect();
                return;
            }

            //include last transferred byte (1)
            this.messageBuffer.AddRange(e.Buffer.Take(e.BytesTransferred));

            //consider last transferred byte
            if (e.Buffer[e.BytesTransferred - 1] == 1)
            {
                //consider array segments as e.BytesTransferred 
                //could include several messages due to racing conditions
                var segments = this.messageBuffer.ToArray().ToArraySegments<byte>(1);
                foreach (var segment in segments)
                {
                    var bytes = segment.ToSegmentArray();
                    Debug.WriteLine("{0}, Class {1}, Thread {2}, Message {3}"
                        , DateTime.Now.ToString("o")
                        , this.GetType().Name
                        , Thread.CurrentThread.ManagedThreadId
                        , UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length));

                    var message = this.messageSerializer.Deserialize(bytes);
                    this.OnMessageReceived(new SocketMessageReceivedEventArgs(message));
                }
                this.messageBuffer.Clear();
            }

            this.socket.ReceiveAsync(e);
        }

 This portion of code calls 2 array extensions that I've detailed below:

        /// <summary>
        /// Creates a collection of <see cref="ArraySegment&lt;T&gt;"/> from an <paramref name="array"/> 
        /// using the specified <paramref name="delimiter"/>.
        /// </summary>
        /// <typeparam name="T">The type of the <paramref name="array"/> elements.</typeparam>
        /// <param name="array">The source array.</param>
        /// <param name="delimiter">The delimiter.</param>
        /// <returns>A collection of <see cref="ArraySegment&lt;T&gt;"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="array"/> is null.</exception>
        public static IList<ArraySegment<T>> ToArraySegments<T>(this T[] array, T delimiter) 
        { 
            if (array == null) 
                throw new ArgumentNullException("array"); 
            
            var segments = new List<ArraySegment<T>>();
            var offset = 0;
            var count = 0;
            for (int i = 0; i < array.Length; i++) 
            {
                if (object.Equals(array[i], delimiter))
                {
                    segments.Add(new ArraySegment<T>(array, offset, count));
                    offset = i + 1;
                    count = 0;
                }
                else
                {
                    count += 1;
                }
            }

            return segments;
        }

        /// <summary>
        /// Creates an array containing elements of an <see cref="ArraySegment&lt;T&gt;"/>.
        /// </summary>
        /// <typeparam name="T">The type of the <paramref name="segment"/> elements.</typeparam>
        /// <param name="segment">The source segment.</param>
        /// <returns>An array containing elements of the specified <paramref name="segment"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="segment"/> is null.</exception>
        public static T[] ToSegmentArray<T>(this ArraySegment<T> segment)
        {
            if (segment == null)
                throw new ArgumentNullException("segment");

            var array = new T[segment.Count];

            Array.Copy(segment.Array, segment.Offset, array, 0, array.Length);

            return array;
        }