첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ Stream 클래스 : 스로틀(Throttle) 스트림 만들기

----------------------------------------------------------------------------------------------------


ThrottleStream.cs


ThrottleStream.cs

 

 

using System;

using System.IO;

using System.Threading;

 

namespace TestProject

{

    /// <summary>

    /// 스로틀 스트림

    /// </summary>

    public class ThrottleStream : Stream

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 무한 바이트 카운트

        /// </summary>

        /// <remarks>초당 전송할 수 있는 무한 바이트 수를 지정하는 상수</remarks>

        private const long INFINITE_BYTE_COUNT = 0;

 

        /// <summary>

        /// 기본 스트림

        /// </summary>

        private Stream baseStream;

 

        /// <summary>

        /// 초당 최대 바이트 카운트

        /// </summary>

        /// <remarks>기본 스트림을 통해 전송될 수 있는 초당 최대 바이트 카운트</remarks>

        private long maximumByteCountPerSecond;

 

        /// <summary>

        /// 마지막 바이트 카운트

        /// </summary>

        /// <remarks>마지막 스로틀 이후에 전송된 바이트 카운트</remarks>

        private long lastByteCount;

 

        /// <summary>

        /// 마지막 시작 시간

        /// </summary>

        /// <remarks>마지막 스로틀 시작 시간 (밀리 초)</remarks>

        private long lastStartTime;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 현재 시간 - CurrentTime

 

        /// <summary>

        /// 현재 시간

        /// </summary>

        /// <remarks>밀리초 단위</remarks>

        protected long CurrentTime

        {

            get

            {

                return Environment.TickCount;

            }

        }

 

        #endregion

        #region 초당 최대 바이트 카운트 - MaximumByteCountPerSecond

 

        /// <summary>

        /// 초당 최대 바이트 카운트

        /// </summary>

        /// <remarks>기본 스트림을 통해 전송될 수 있는 초당 최대 바이트 카운트</remarks>

        public long MaximumByteCountPerSecond

        {

            get

            {

                return this.maximumByteCountPerSecond;

            }

            set

            {

                if(this.maximumByteCountPerSecond != value)

                {

                    this.maximumByteCountPerSecond = value;

 

                    Reset();

                }

            }

        }

 

        #endregion

 

        #region 읽기 가능 여부 - CanRead

 

        /// <summary>

        /// 읽기 가능 여부

        /// </summary>

        public override bool CanRead

        {

            get

            {

                return this.baseStream.CanRead;

            }

        }

 

        #endregion

        #region 탐색 가능 여부 - CanSeek

 

        /// <summary>

        /// 탐색 가능 여부

        /// </summary>

        public override bool CanSeek

        {

            get

            {

                return this.baseStream.CanSeek;

            }

        }

 

        #endregion

        #region 쓰기 가능 여부 - CanWrite

 

        /// <summary>

        /// 쓰기 가능 여부

        /// </summary>

        public override bool CanWrite

        {

            get

            {

                return this.baseStream.CanWrite;

            }

        }

 

        #endregion

        #region 길이 - Length

 

        /// <summary>

        /// 길이

        /// </summary>

        public override long Length

        {

            get

            {

                return this.baseStream.Length;

            }

        }

 

        #endregion

        #region 위치 - Position

 

        /// <summary>

        /// 위치

        /// </summary>

        public override long Position

        {

            get

            {

                return this.baseStream.Position;

            }

            set

            {

                this.baseStream.Position = value;

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - ThrottleStream(baseStream, maximumByteCountPerSecond)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="baseStream">기본 스트림</param>

        /// <param name="maximumByteCountPerSecond">초당 최대 바이트 카운트</param>

        public ThrottleStream(Stream baseStream, long maximumByteCountPerSecond)

        {

            if(baseStream == null)

            {

                throw new ArgumentNullException("baseStream");

            }

 

            if(maximumByteCountPerSecond < 0)

            {

                throw new ArgumentOutOfRangeException("maximumByteCountPerSecond", maximumByteCountPerSecond,

                    "초당 최대 바이트 카운트는 음수가 될 수 없습니다.");

            }

 

            this.baseStream                = baseStream;

            this.maximumByteCountPerSecond = maximumByteCountPerSecond;

            this.lastStartTime             = CurrentTime;

            this.lastByteCount             = 0;

        }

 

        #endregion

        #region 생성자 - ThrottleStream(baseStream)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="baseStream">기본 스트림</param>

        public ThrottleStream(Stream baseStream) : this(baseStream, ThrottleStream.INFINITE_BYTE_COUNT)

        {

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 버퍼 비우기 - Flush()

 

        /// <summary>

        /// 버퍼 비우기

        /// </summary>

        public override void Flush()

        {

            this.baseStream.Flush();

        }

 

        #endregion

        #region 읽기 - Read(bufferArray, offset, count)

 

        /// <summary>

        /// 읽기

        /// </summary>

        /// <param name="bufferArray">버퍼 배열</param>

        /// <param name="offset">오프셋</param>

        /// <param name="count">카운트</param>

        /// <returns>실제 읽은 바이트 카운트</returns>

        public override int Read(byte[] bufferArray, int offset, int count)

        {

            Throttle(count);

 

            return this.baseStream.Read(bufferArray, offset, count);

        }

 

        #endregion

        #region 탐색하기 - Seek(offset, seekOrigin)

 

        /// <summary>

        /// 탐색하기

        /// </summary>

        /// <param name="offset">오프셋</param>

        /// <param name="seekOrigin">탐색 기준</param>

        /// <returns>위치</returns>

        public override long Seek(long offset, SeekOrigin seekOrigin)

        {

            return this.baseStream.Seek(offset, seekOrigin);

        }

 

        #endregion

        #region 길이 설정하기 - SetLength(value)

 

        /// <summary>

        /// 길이 설정하기

        /// </summary>

        /// <param name="value"></param>

        public override void SetLength(long value)

        {

            this.baseStream.SetLength(value);

        }

 

        #endregion

        #region 쓰기 - Write(bufferArray, offset, count)

 

        /// <summary>

        /// 쓰기

        /// </summary>

        /// <param name="bufferArray">버퍼 배열</param>

        /// <param name="offset">오프셋</param>

        /// <param name="count">카운트</param>

        public override void Write(byte[] bufferArray, int offset, int count)

        {

            Throttle(count);

 

            this.baseStream.Write(bufferArray, offset, count);

        }

 

        #endregion

        #region 문자열 구하기 - ToString()

 

        /// <summary>

        /// 문자열 구하기

        /// </summary>

        /// <returns>문자열</returns>

        public override string ToString()

        {

            return this.baseStream.ToString();

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 스로틀 처리하기 - Throttle(bufferSizeInByteCount)

 

        /// <summary>

        /// 스로틀 처리하기

        /// </summary>

        /// <param name="bufferSizeInByteCount">바이트 카운트 단위 버퍼 크기</param>

        /// <remarks>지정된 버퍼 크기로 통신을 제한한다.</remarks>

        protected void Throttle(int bufferSizeInByteCount)

        {

            if(this.maximumByteCountPerSecond <= 0 || bufferSizeInByteCount <= 0)

            {

                return;

            }

 

            this.lastByteCount += bufferSizeInByteCount;

 

            long millisecondCountElapsed = CurrentTime - this.lastStartTime;

 

            if(millisecondCountElapsed > 0)

            {

                long bps = this.lastByteCount * 1000L / millisecondCountElapsed;

 

                if(bps > this.maximumByteCountPerSecond)

                {

                    long wakeElapsed = this.lastByteCount * 1000L / this.maximumByteCountPerSecond;

 

                    int toSleep = (int)(wakeElapsed - millisecondCountElapsed);

 

                    if(toSleep > 1)

                    {

                        try

                        {

                            Thread.Sleep(toSleep);

                        }

                        catch(ThreadAbortException)

                        {

                        }

 

                        Reset();

                    }

                }

            }

        }

 

        #endregion

        #region 리셋하기 - Reset()

 

        /// <summary>

        /// 리셋하기

        /// </summary>

        /// <remarks>바이트 수를 0으로 재설정하고 시작 시간을 현재 시간으로 재설정합니다.</remarks>

        protected void Reset()

        {

            long difference = CurrentTime - this.lastStartTime;

 

            if(difference > 1000)

            {

                this.lastByteCount = 0;

 

                this.lastStartTime = CurrentTime;

            }

        }

 

        #endregion

    }

}

 

----------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker
TAG

댓글을 달아 주세요