블로그 이미지
따시쿵

calendar

1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

Notice

2015. 5. 30. 14:22 C# with TCP/IP
프로그램 설명

서버-클라이언트로 구성 된 파일 전송 예제입니다.
한 번에 전송되는 양은 8k 이며, 양방향 통신을 합니다.

1. 기본 클래스와 UI 파일입니다.

기본 클래스 : SocketAcceptedEventArgs, Listener, PacketWriter, PacketReader

Listener.cs PacketIO.cs


UI 파일 : main.cs (서버와 클라이언트가 공통된 UI 를 사용함)


2. QueueType, TransferQueue class 를 정의합니다.

enum QueueType define : 다운로드인지, 업로드인지 구분하는 enum
    public enum QueueType : byte
    {
        Download,
        Upload
    }

class TransferQueue define : 전송되는 queue 에 저장하는 class
    public class TransferQueue
    {
        public static TransferQueue CreateUploadQueue(TransferClient client, string fileName)
        {
            try
            {
                var queue = new TransferQueue();
                queue.Filename = Path.GetFileName(fileName);
                queue.Client = client;
                queue.Type = QueueType.Upload;
                queue.FS = new FileStream(fileName, FileMode.Open);
                queue.Thread = new Thread(new ParameterizedThreadStart(transferProc));
                queue.Thread.IsBackground = true;
                queue.ID = Program.Rand.Next();
                queue.Length = queue.FS.Length;

                return queue;
            }
            catch
            {
                return null;
            }
        }

        public static TransferQueue CreateDownloadQueue(TransferClient client, int id, string saveName, long length)
        {
            try
            {
                var queue = new TransferQueue();
                queue.Filename = Path.GetFileName(saveName);
                queue.Client = client;
                queue.Type = QueueType.Download;
                queue.FS = new FileStream(saveName, FileMode.Create);
                queue.FS.SetLength(length);
                queue.Length = length;
                queue.ID = id;

                return queue;
            }
            catch
            {
                return null;
            }
        }

        private const int FILE_BUFFER_SIZE = 8175;
        private static byte[] file_buffer = new byte[FILE_BUFFER_SIZE];

        private ManualResetEvent pauseEvent;

        public int ID;
        public int Progress, LastProgress;

        public long Transferred;
        public long Index;
        public long Length;

        public bool Running;
        public bool Paused;

        public string Filename;

        public QueueType Type;

        public TransferClient Client;
        public Thread Thread;
        public FileStream FS;

        private TransferQueue()
        {
            pauseEvent = new ManualResetEvent(true);
            Running = true;
        }

        public void Start()
        {
            Running = true;
            Thread.Start(this);
        }

        public void Stop()
        {
            Running = false;
        }

        public void Pause()
        {
            if(!Paused)
            {
                pauseEvent.Reset();
            }
            else
            {
                pauseEvent.Set();
            }

            Paused = !Paused;
        }

        public void Close()
        {
            try
            {
                Client.Transfers.Remove(ID);
            }
            catch
            { 
            
            }

            Running = false;
            FS.Close();
            pauseEvent.Dispose();

            Client = null;
        }

        public void Write(byte[] bytes, long index)
        {
            lock(this)
            {
                FS.Position = index;
                FS.Write(bytes, 0, bytes.Length);
                Transferred += bytes.Length;
            }
        }

        private static void transferProc(object o)
        {
            TransferQueue queue = (TransferQueue)o;

            while(queue.Running && queue.Index < queue.Length)
            {
                queue.pauseEvent.WaitOne();

                if (!queue.Running)
                    break;

                lock(file_buffer)
                {
                    queue.FS.Position = queue.Index;

                    int read = queue.FS.Read(file_buffer, 0, file_buffer.Length);

                    PacketWriter pw = new PacketWriter();
                    pw.Write((byte)Headers.Chunk);
                    pw.Write(queue.ID);
                    pw.Write(queue.Index);
                    pw.Write(read);
                    pw.Write(file_buffer, 0, read);

                    queue.Transferred += read;
                    queue.Index += read;

                    queue.Client.Send(pw.GetBytes());

                    queue.Progress = (int)((queue.Transferred * 100) / queue.Length);

                    if(queue.LastProgress < queue.Progress)
                    {
                        queue.LastProgress = queue.Progress;

                        queue.Client.callProgressChanged(queue);
                    }

                    Thread.Sleep(1);
                }
            }
            queue.Close();
        }
    }

3. queue 작동 방법을 정의합니다.
    public enum Headers : byte
    {
        Queue,
        Start,
        Stop,
        pause,
        Chunk
    }

4. TransferClient class 정의 합니다.


transferClient calss define : 클라이언트 전송 class

    public class TransferClient
    {
        private Socket _baseSocket;

        private byte[] _buffer = new byte[8192];

        private ConnectCallback _connectCallback;

        private Dictionary<int, TransferQueue> _transfers = new Dictionary<int, TransferQueue>();

        public Dictionary<int, TransferQueue> Transfers
        {
            get { return _transfers; }
        }

        public bool Closed
        {
            get;
            private set;
        }

        public string OutputFolder
        {
            get;
            set;
        }

        public IPEndPoint EndPoint
        {
            get;
            private set;
        }

        public event TransferEventHandler Queued;
        public event TransferEventHandler ProgressChanged;
        public event TransferEventHandler Stopped;
        public event TransferEventHandler Complete;
        public event EventHandler Disconnected;

        public TransferClient()
        {
            _baseSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public TransferClient(Socket sock)
        {
            _baseSocket = sock;
            EndPoint = (IPEndPoint)_baseSocket.RemoteEndPoint;
        }

        public void Connect(string hostName, int port, ConnectCallback callback)
        {
            _connectCallback = callback;
            _baseSocket.BeginConnect(hostName, port, connectionCallback, null);
        }

        private void connectionCallback(IAsyncResult ar)
        {
            string error = null;
            try
            {
                _baseSocket.EndConnect(ar);
                EndPoint = (IPEndPoint)_baseSocket.RemoteEndPoint;
            }
            catch(Exception ex)
            {
                error = ex.Message.ToString();
            }

            _connectCallback(this, error);
        }

        public void Run()
        {
            try
            {
                _baseSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.Peek, receiveCallback, null);
            }
            catch
            {
                Close();
            }
        }

        public void QueueTransfer(string fileName)
        {
            try
            {
                TransferQueue queue = TransferQueue.CreateUploadQueue(this, fileName);
                _transfers.Add(queue.ID, queue);
                PacketWriter pw = new PacketWriter();
                pw.Write((byte)Headers.Queue);
                pw.Write(queue.ID);
                pw.Write(queue.Filename);
                pw.Write(queue.Length);
                Send(pw.GetBytes());

                if(Queued != null)
                {
                    Queued(this, queue);
                }
            }
            catch
            {

            }
        }
        
        public void StartTransfer(TransferQueue queue)
        {
            PacketWriter pw = new PacketWriter();
            pw.Write((byte)Headers.Start);
            pw.Write(queue.ID);
            Send(pw.GetBytes());
        }

        public void StopTransfer(TransferQueue queue)
        {
            if(queue.Type == QueueType.Upload)
            {
                queue.Stop();
            }

            PacketWriter pw = new PacketWriter();
            pw.Write((byte)Headers.Stop);
            pw.Write(queue.ID);
            Send(pw.GetBytes());
            queue.Close();
        }

        public void PauseTransfer(TransferQueue queue)
        {
            if(queue.Type == QueueType.Upload)
            {
                queue.Pause();
                return;
            }

            PacketWriter pw = new PacketWriter();
            pw.Write((byte)Headers.pause);
            pw.Write(queue.ID);
            Send(pw.GetBytes());
        }

        public int GetOverallProgress()
        {
            int overall = 0;

            foreach(KeyValuePair<int, TransferQueue> pair in _transfers)
            {
                overall += pair.Value.Progress;
            }
            System.Diagnostics.Trace.WriteLine(string.Format("1. overall = {0}", overall));
            if (overall > 0)
            {
                overall = (overall * 100) / (_transfers.Count * 100);
            }

            System.Diagnostics.Trace.WriteLine(string.Format("2. overall = {0}", overall));
            if (overall > 100)
                overall = 100;

            return overall;
        }

        public void Send(byte[] data)
        {
            if (Closed)
                return;

            lock(this)
            {
                try
                {
                    _baseSocket.Send(BitConverter.GetBytes(data.Length), 0, 4, SocketFlags.None);
                    _baseSocket.Send(data, 0, data.Length, SocketFlags.None);
                }
                catch
                {
                    Close();
                }
            }
        }

        public void Close()
        {
            Closed = true;
            _baseSocket.Close();
            if (_transfers != null)
            {
                _transfers.Clear();
                _transfers = null;
            }
            _buffer = null;
            OutputFolder = null;

            if (Disconnected != null)
                Disconnected(this, EventArgs.Empty);
        }

        private void process()
        {
            PacketReader pr = new PacketReader(_buffer);

            Headers header = (Headers)pr.ReadByte();

            switch(header)
            {
                case Headers.Queue:
                    {
                        int id = pr.ReadInt32();
                        string fileName = pr.ReadString();
                        long length = pr.ReadInt64();

                        TransferQueue queue = TransferQueue.CreateDownloadQueue(this, id, Path.Combine(OutputFolder, Path.GetFileName(fileName)), length);

                        _transfers.Add(id, queue);

                        if (Queued != null)
                        {
                            Queued(this, queue);
                        }

                    }
                    break;
                case Headers.Start:
                    {
                        int id = pr.ReadInt32();

                        if(_transfers.ContainsKey(id))
                        {
                            _transfers[id].Start();
                        }
                    }
                    break;
                case Headers.Stop:
                    {
                        int id = pr.ReadInt32();

                        if (_transfers.ContainsKey(id))
                        {
                            TransferQueue queue = _transfers[id];

                            queue.Stop();
                            queue.Close();

                            if(Stopped != null)
                            {
                                Stopped(this, queue);
                            }

                            _transfers.Remove(id);
                        }
                    }
                    break;
                case Headers.pause:
                    {
                        int id = pr.ReadInt32();

                        if(_transfers.ContainsKey(id))
                        {
                            _transfers[id].Pause();
                        }
                    }
                    break;
                case Headers.Chunk:
                    {
                        int id = pr.ReadInt32();
                        long index = pr.ReadInt64();
                        int size = pr.ReadInt32();
                        byte[] buffer = pr.ReadBytes(size);

                        TransferQueue queue = _transfers[id];

                        queue.Write(buffer, index);

                        queue.Progress = (int)((queue.Transferred * 100) / queue.Length);

                        if(queue.LastProgress < queue.Progress)
                        {
                            queue.LastProgress = queue.Progress;

                            if(ProgressChanged != null)
                            {
                                ProgressChanged(this, queue);
                            }

                            if(queue.Progress == 100)
                            {
                                queue.Close();

                                if(Complete != null)
                                {
                                    Complete(this, queue);
                                }
                            }
                        }
                    }
                    break;
            }
            pr.Dispose();
        }

        private void receiveCallback(IAsyncResult ar)
        {
            try
            {
                int found = _baseSocket.EndReceive(ar);

                if(found >= 4)
                {
                    _baseSocket.Receive(_buffer, 0, 4, SocketFlags.None);

                    int size = BitConverter.ToInt32(_buffer, 0);

                    int read = _baseSocket.Receive(_buffer, 0, size, SocketFlags.None);

                    while(read < size)
                    {
                        read += _baseSocket.Receive(_buffer, read, size - read, SocketFlags.None);
                    }

                    process();
                }

                Run();
            }
            catch
            {
                Close();
            }
        }

        internal void callProgressChanged(TransferQueue queue)
        {
            if (ProgressChanged != null)
                ProgressChanged(this, queue);
        }
    }

5. UI method 를 정의 합니다.


실행 화면




소스 파일 : 
posted by 따시쿵