안녕하세요. 언제나 휴일입니다.
앞에서 P2P 메신저의 숏 메시지와 파일 송수신 부분을 구현했어요.
그리고 .NET 리모팅 서비스 제작 방법도 실습했었죠.
이번에는 P2P 메신저의 인증 서비스 부분을 구현해 볼 거예요.
현재 구현은 P2P에서 사용자가 상대 IP 주소와 포트 정보를 설정하고 있어요.
이 부분을 인증 서비스를 구현하여 상대 ID만 선택하여 메시지와 파일을 전송할 수 있게 할 거예요.
이를 위해 먼저 인증 서비스를 위한 공용 라이브러리를 제작합시다.
프로젝트는 클래스 라이브러리(.NET Framework)로 제작합니다.
using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; namespace EHAAALib { class UserInfo { internal string ID { get; private set; } internal DateTime LastKA { get; set; } internal string IPStr { get; set; } internal int SPort { get; set; } internal int FPort { get; set; } internal int BPort { get; set; } internal UserInfo(string id,string ip, int sport,int fport,int bport) { ID = id; IPStr = ip; SPort = sport; FPort = fport; BPort = bport; } } public class EHAAA:MarshalByRefObject { const string sfname = "member.xsl"; const string dfname = "member.xml"; DataTable mtb = new DataTable("회원"); Dictionary<string, UserInfo> ui_dic = new Dictionary<string, UserInfo>(); Timer timer = null; public EHAAA() { Initialize(); } ~EHAAA() { mtb.WriteXml(dfname); } private void Initialize() { timer = new Timer(CheckKeepAlive); timer.Change(0, 3000); if(File.Exists(sfname)) { mtb.ReadXmlSchema(sfname); if(File.Exists(dfname)) { mtb.ReadXml(dfname); } } else { DesignMTB(); } } private void DesignMTB() { DataColumn dc_id = new DataColumn("id", typeof(string)); dc_id.Unique = true; dc_id.AllowDBNull = false; mtb.Columns.Add(dc_id); DataColumn dc_pw = new DataColumn("pw", typeof(string)); dc_pw.AllowDBNull = false; mtb.Columns.Add(dc_pw); DataColumn[] pkeys = new DataColumn[] { dc_id }; mtb.PrimaryKey = pkeys; mtb.WriteXmlSchema(sfname); } void CheckKeepAlive(object state) { Console.Write("."); List dlist = new List(); foreach(KeyValuePair<string,UserInfo> ui in ui_dic) { TimeSpan ts = DateTime.Now - ui.Value.LastKA; if(ts.TotalSeconds>9) { dlist.Add(ui.Key); } } foreach(string id in dlist) { ui_dic.Remove(id); Logout2(id); } } private void Logout2(string id) { try { foreach (UserInfo ui in ui_dic.Values) { string oip = ui.IPStr; int obport = ui.BPort; SendUserInfoAsync(oip, obport, id, "", 0, 0); } } catch { } } public void Logout(string id) { if(ui_dic.ContainsKey(id) == false) { return; } ui_dic.Remove(id); Logout2(id); } public bool Join(string id, string pw) { try { DataRow dr = mtb.NewRow(); dr["id"] = id; dr["pw"] = pw; mtb.Rows.Add(dr); return true; } catch(Exception ex) { Console.WriteLine(ex.Message); return false; } } public void Withdraw(string id, string pw) { if(ui_dic.ContainsKey(id)) { DataRow dr = mtb.Rows.Find(id); if(dr == null) { return; } if(dr["pw"].ToString() == pw) { mtb.Rows.Remove(dr); Logout(id); } } } public int Login(string id,string pw) { try { DataRow dr = mtb.Rows.Find(id); if(dr == null) { return 1;//미가입 ID } if(ui_dic.ContainsKey(id) == false) { if(dr["pw"].ToString() == pw) { return 0;//로긴 성공 } return 3;//비밀번호 틀림 } return 2;//이미 로긴 중 } catch(Exception ex) { Console.WriteLine(ex.Message); return 3;//예외 발생 } } public void KeepAlive(string id) { try { if(ui_dic.ContainsKey(id)) { ui_dic[id].LastKA = DateTime.Now; } } catch { } } public void KeepAlive(string id,string ipstr,int sport,int fport,int bport) { Console.WriteLine("{0}의 첫 번째 KeepAlive,{1},{2}!!!", id, ipstr, bport); try { UserInfo ui = new UserInfo(id, ipstr, sport, fport, bport); foreach (UserInfo oui in ui_dic.Values) { Console.WriteLine("Other:{0}", oui.ID); string oip = oui.IPStr; int osport = oui.SPort; int ofport = oui.FPort; int obport = oui.BPort; SendUserInfoAsync(oip, obport, id, ipstr, sport, fport); SendUserInfoAsync(ipstr, bport, oui.ID, oip, osport, ofport); } ui_dic[id] = ui; ui.LastKA = DateTime.Now; } catch { } } delegate void SUIDele(string oip, int obport, string id, string ipstr, int sport, int fport); private void SendUserInfoAsync(string oip, int obport, string id, string ipstr, int sport, int fport) { SUIDele dele = SendUserInfo; dele.BeginInvoke(oip, obport, id, ipstr, sport, fport, null, null); } private void SendUserInfo(string oip, int obport, string id, string ipstr, int sport, int fport) { try { Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint iep = new IPEndPoint(IPAddress.Parse(oip), obport); sock.Connect(iep); byte[] packet = new byte[1024]; MemoryStream ms = new MemoryStream(packet); BinaryWriter bw = new BinaryWriter(ms); bw.Write(id); bw.Write(ipstr); bw.Write(sport); bw.Write(fport); bw.Close(); ms.Close(); sock.Send(packet); sock.Close(); } catch { //로그 작성 } } } }