안녕하세요. 언제나 휴일에 언휴예요.
이번 강의는 파일 수신 서버 구현 실습이예요.
1. 이벤트 인자 및 대리자 구현
연결 요청 수락 이벤트 인자 및 대리자
using System; using System.Net; namespace 파일_수신_서버 { public delegate void AcceptedEventHandler(object sender, AcceptedEventArgs e); public class AcceptedEventArgs:EventArgs { public IPEndPoint RemoteEndPoint { get; private set; } public string IPStr { get { return RemoteEndPoint.Address.ToString(); } } public int Port { get { return RemoteEndPoint.Port; } } public AcceptedEventArgs(IPEndPoint rep) { RemoteEndPoint = rep; } } }
연결 종료 이벤트 인자 및 대리자
using System.Net; namespace 파일_수신_서버 { public delegate void ClosedEventHandler(object sender, ClosedEventArgs e); public class ClosedEventArgs { public IPEndPoint RemoteEndPoint { get; private set; } public string IPStr { get { return RemoteEndPoint.Address.ToString(); } } public int Port { get { return RemoteEndPoint.Port; } } public ClosedEventArgs(IPEndPoint rep) { RemoteEndPoint = rep; } } }
파일 이름 수신 이벤트 인자 및 대리자
using System; using System.Net; namespace 파일_수신_서버 { public delegate void RecvFileNameEventHandler(object sender, RecvFileNameEventArgs e); public class RecvFileNameEventArgs:EventArgs { public IPEndPoint RemoteEndPoint { get; private set; } public string FileName { get; private set; } public RecvFileNameEventArgs(string fname,IPEndPoint rep) { FileName = fname; RemoteEndPoint = rep; } } }
파일 길이 수신 이벤트 인자 및 대리자
using System; using System.Net; namespace 파일_수신_서버 { public delegate void FIleLengthRecvEventHandler(object sender, FIleLengthRecvEventArgs e); public class FIleLengthRecvEventArgs:EventArgs { public IPEndPoint RemoteEndPoint { get; private set; } public string FileName { get; private set; } public long Length { get; private set; } public FIleLengthRecvEventArgs(string fname,IPEndPoint rep,long length) { FileName = fname; RemoteEndPoint = rep; Length = length; } } }
파일 데이터 수신 이벤트 인자 및 대리자
using System; using System.Net; namespace 파일_수신_서버 { public delegate void FileDataRecvEventHandler(object sender, FileDataRecvEventArgs e); public class FileDataRecvEventArgs:EventArgs { public IPEndPoint RemoteEndPoint { get; private set; } public string FileName { get; private set; } public long RemainLength { get; private set; } public byte[] Data { get; private set; } public FileDataRecvEventArgs(string fname,IPEndPoint rep, long rlen,byte[] data) { FileName = fname; RemoteEndPoint = rep; RemainLength = rlen; Data = data; } } }
2. 파일 수신 서버 클래스 구현
/* https://ehpub.co.kr * 파일 수신 서버 */ using System; using System.Diagnostics.Eventing.Reader; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; namespace 파일_수신_서버 { public class FileRecvServ { const int MAX_PACK_SIZE = 1024; public event AcceptedEventHandler AcceptedEventHandler = null; public event ClosedEventHandler ClosedEventHandler = null; public event RecvFileNameEventHandler RecvFileNameEventHandler = null; public event FIleLengthRecvEventHandler FIleLengthRecvEventHandler = null; public event FileDataRecvEventHandler FileDataRecvEventHandler = null; public string IPStr { get; private set; } public int Port { get; private set; } public FileRecvServ(string ip,int port) { IPStr = ip; Port = port; } Socket sock; public bool Start() { try { sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ipaddr = IPAddress.Parse(IPStr); IPEndPoint iep = new IPEndPoint(ipaddr, Port); sock.Bind(iep); sock.Listen(5); AcceptLoopAsync(); } catch { return false; } return true; } delegate void AcceptDele(); private void AcceptLoopAsync() { AcceptDele dele = AcceptLoop; dele.BeginInvoke(null, null); } private void AcceptLoop() { while(true) { Socket dosock = sock.Accept(); DoItAsync(dosock); } } Thread thread; private void DoItAsync(object dosock) { ParameterizedThreadStart pts = DoIt; thread = new Thread(pts); thread.Start(dosock); } void DoIt(object osock) { Socket dosock = osock as Socket; IPEndPoint rep = dosock.RemoteEndPoint as IPEndPoint; if(AcceptedEventHandler != null) { AcceptedEventHandler(this, new AcceptedEventArgs(rep)); } string fname = RecvFileName(dosock); if(RecvFileNameEventHandler != null) { RecvFileNameEventHandler(this, new RecvFileNameEventArgs(fname, rep)); } long length = RecvFileLength(dosock); if(FIleLengthRecvEventHandler !=null) { FIleLengthRecvEventHandler(this, new FIleLengthRecvEventArgs(fname, rep, length)); } RecvFile(dosock, fname, length); dosock.Close(); if(ClosedEventHandler != null) { ClosedEventHandler(this, new ClosedEventArgs(rep)); } } private void RecvFile(Socket dosock, string fname, long length) { IPEndPoint rep = dosock.RemoteEndPoint as IPEndPoint; byte[] packet = new byte[MAX_PACK_SIZE]; while(length>=MAX_PACK_SIZE) { int rlen = dosock.Receive(packet); if(FileDataRecvEventHandler != null) { byte[] pd2 = new byte[rlen]; MemoryStream ms = new MemoryStream(pd2); ms.Write(packet, 0, rlen); FileDataRecvEventHandler(this, new FileDataRecvEventArgs(fname, rep, length, pd2)); } length -= rlen; } dosock.Receive(packet, (int)length, SocketFlags.None); if (FileDataRecvEventHandler != null) { byte[] pd2 = new byte[length]; MemoryStream ms = new MemoryStream(pd2); ms.Write(packet, 0,(int)length); FileDataRecvEventHandler(this, new FileDataRecvEventArgs(fname, rep, 0, pd2)); } } private long RecvFileLength(Socket dosock) { byte[] packet = new byte[8]; dosock.Receive(packet); MemoryStream ms = new MemoryStream(packet); BinaryReader br = new BinaryReader(ms); long length = br.ReadInt64(); br.Close(); ms.Close(); return length; } private string RecvFileName(Socket dosock) { byte[] packet = new byte[MAX_PACK_SIZE]; dosock.Receive(packet); MemoryStream ms = new MemoryStream(packet); BinaryReader br = new BinaryReader(ms); string fname = br.ReadString(); br.Close(); ms.Close(); return fname; } } }
3. Program.cs 에서 사용
/* https://ehpub.co.kr * 파일 수신 서버 */ using System; using System.IO; namespace 파일_수신_서버 { class Program { static void Main(string[] args) { FileRecvServ fs = new FileRecvServ("192.168.219.106", 10340); fs.AcceptedEventHandler += Fs_AcceptedEventHandler; fs.ClosedEventHandler += Fs_ClosedEventHandler; fs.RecvFileNameEventHandler += Fs_RecvFileNameEventHandler; fs.FIleLengthRecvEventHandler += Fs_FIleLengthRecvEventHandler; fs.FileDataRecvEventHandler += Fs_FileDataRecvEventHandler; fs.Start(); Console.ReadKey(); } static long length; static FileStream fs; private static void Fs_FileDataRecvEventHandler(object sender, FileDataRecvEventArgs e) { Console.WriteLine("{0}:{1}에서 {2} 남은 길이:{3}", e.RemoteEndPoint.Address, e.RemoteEndPoint.Port, e.FileName, e.RemainLength); fs.Write(e.Data, 0, e.Data.Length); if(e.RemainLength==0) { fs.Close(); } } private static void Fs_FIleLengthRecvEventHandler(object sender, FIleLengthRecvEventArgs e) { Console.WriteLine("{0}:{1}에서 {2} 길이:{3}", e.RemoteEndPoint.Address, e.RemoteEndPoint.Port, e.FileName,e.Length); length = e.Length; } private static void Fs_RecvFileNameEventHandler(object sender, RecvFileNameEventArgs e) { Console.WriteLine("{0}:{1}에서 {2}전송 시작", e.RemoteEndPoint.Address, e.RemoteEndPoint.Port, e.FileName); fs = File.Create(e.FileName); } private static void Fs_ClosedEventHandler(object sender, ClosedEventArgs e) { Console.WriteLine("{0}:{1}와 연결 해제", e.IPStr, e.Port); } private static void Fs_AcceptedEventHandler(object sender, AcceptedEventArgs e) { Console.WriteLine("{0}:{1}와 연결", e.IPStr, e.Port); } } }