파일 전송 클라이언트 구현 [네트워크 프로그래밍 C#]

안녕하세요. 언제나 휴일에 언휴예요.

이번 강의는 파일 전송 클라이언트를 구현하는 실습입니다.

1. 파일 데이터 전송 이벤트 인자 및 대리자 구현

using System;

namespace 파일_전송_클라이언트
{
    public delegate void SendFileDataEventHandler(object sender, SendFileDataEventArgs e);
    public class SendFileDataEventArgs:EventArgs
    {
        public string FileName
        {
            get;
            private set;
        }
        public long Remain
        {
            get;
            private set;
        }
        public SendFileDataEventArgs(string fname, long remain)
        {
            FileName = fname;
            Remain = remain;
        }
    }
}

2. 파일 전송 클라이언트 클래스 구현

/*                                                                                                                                            https://ehpub.co.kr
 *                                                                                                                                      파일 전송 클라이언트        
 */

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;

namespace 파일_전송_클라이언트
{
    public class FileSendClient
    {
        const int MAX_PACK_SIZE = 1024;
        public event SendFileDataEventHandler SendFileDataEventHandler = null;

        public string IPStr
        {
            get;
            private set;
        }
        public int Port
        {
            get;
            private set;
        }

        public FileSendClient(string ip, int port)
        {
            IPStr = ip;
            Port = port;
        }

        delegate void SendDele(string fname);
        public void SendAsync(string fname)
        {
            SendDele dele = Send;
            dele.BeginInvoke(fname, null, null);
        }
        public void Send(string fname)
        {
            if(File.Exists(fname)==false)
            {
                return;
            }
            Socket sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            IPEndPoint iep = new IPEndPoint(IPAddress.Parse(IPStr), Port);
            sock.Connect(iep);

            byte[] packet = new byte[MAX_PACK_SIZE];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write(fname);
            bw.Close();
            ms.Close();
            sock.Send(packet);

            FileStream fs = File.OpenRead(fname);
            ms = new MemoryStream(packet);
            bw = new BinaryWriter(ms);
            bw.Write(fs.Length);
            sock.Send(packet, 0, 8, SocketFlags.None);
            ms.Close();
            bw.Close();

            long remain = fs.Length;
            int sl;
            while(remain>=MAX_PACK_SIZE)
            {
                fs.Read(packet, 0, MAX_PACK_SIZE);
                sl = sock.Send(packet);
                while(sl<MAX_PACK_SIZE)
                {
                    sl += sock.Send(packet, sl, MAX_PACK_SIZE - sl, SocketFlags.None);
                }
                if(SendFileDataEventHandler != null)
                {
                    SendFileDataEventHandler(this, new SendFileDataEventArgs(fname, remain));
                }
                remain -= MAX_PACK_SIZE;
            }
            fs.Read(packet, 0, (int)remain);
            sl = sock.Send(packet);
            while (sl < remain)
            {
                sl += sock.Send(packet, sl, (int)remain - sl, SocketFlags.None);
            }
            remain = 0;
            if (SendFileDataEventHandler != null)
            {
                SendFileDataEventHandler(this, new SendFileDataEventArgs(fname, remain));
            }
            fs.Close();
            sock.Close();
        }
    }
}

3. Program.cs 에서 사용

/* https://ehpub.co.kr
 * 파일 전송 클라이언트
 */

using System;

namespace 파일_전송_클라이언트
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("서버 IP:");
            string ip = Console.ReadLine();

            int port = 10340;
            Console.Write("포트 번호:{0}",port);

            FileSendClient fsc = new FileSendClient(ip, port);
            fsc.SendFileDataEventHandler += Fsc_SendFileDataEventHandler;

            Console.Write("전송할 파일명:");
            string fname = Console.ReadLine();
            fsc.SendAsync(fname);

            Console.ReadKey();
        }

        private static void Fsc_SendFileDataEventHandler(object sender, SendFileDataEventArgs e)
        {
            Console.WriteLine("{0}파일 {1}bytes 남았음.", e.FileName, e.Remain);
        }
    }
}