From 3230581fb5c780cfceabaa1a00c6f564e720306b Mon Sep 17 00:00:00 2001 From: syneffort Date: Thu, 9 Feb 2023 13:40:04 +0900 Subject: [PATCH] login --- Chat/Client/Client.csproj | 4 ++ Chat/Client/LoginForm.Designer.cs | 2 +- Chat/Client/LoginForm.cs | 49 +++++++++++++++++--- Chat/Client/Singleton.cs | 62 +++++++++++++++++++++++++- Chat/Core/IPacket.cs | 13 ++++++ Chat/Core/LoginRequestPacket.cs | 74 +++++++++++++++++++++++++++++++ Chat/Core/LoginResponsePacket.cs | 49 ++++++++++++++++++++ Chat/Core/PServer.cs | 11 ++++- Chat/Core/PacketType.cs | 14 ++++++ Chat/Core/StatusCode.cs | 13 ++++++ 10 files changed, 282 insertions(+), 9 deletions(-) create mode 100644 Chat/Core/IPacket.cs create mode 100644 Chat/Core/LoginRequestPacket.cs create mode 100644 Chat/Core/LoginResponsePacket.cs create mode 100644 Chat/Core/PacketType.cs create mode 100644 Chat/Core/StatusCode.cs diff --git a/Chat/Client/Client.csproj b/Chat/Client/Client.csproj index b57c89e..1b9dd3d 100644 --- a/Chat/Client/Client.csproj +++ b/Chat/Client/Client.csproj @@ -8,4 +8,8 @@ enable + + + + \ No newline at end of file diff --git a/Chat/Client/LoginForm.Designer.cs b/Chat/Client/LoginForm.Designer.cs index 5ce983a..f51fef5 100644 --- a/Chat/Client/LoginForm.Designer.cs +++ b/Chat/Client/LoginForm.Designer.cs @@ -49,7 +49,7 @@ this.tbxId.Location = new System.Drawing.Point(79, 12); this.tbxId.Name = "tbxId"; this.tbxId.Size = new System.Drawing.Size(181, 23); - this.tbxId.TabIndex = 1; + this.tbxId.TabIndex = 0; // // label2 // diff --git a/Chat/Client/LoginForm.cs b/Chat/Client/LoginForm.cs index 490666b..5fb1992 100644 --- a/Chat/Client/LoginForm.cs +++ b/Chat/Client/LoginForm.cs @@ -1,3 +1,6 @@ +using Core; +using System.Net.Sockets; + namespace Client { public partial class LoginForm : Form @@ -5,21 +8,55 @@ namespace Client public LoginForm() { InitializeComponent(); + InitInstance(); } - private void btnLogin_Click(object sender, EventArgs e) + private void InitInstance() { - if (string.IsNullOrEmpty(tbxId.Text) || string.IsNullOrEmpty(tbxNickname.Text)) + Singleton.Instance.LoginResponsed += LoginResponsed; + FormClosing += LoginForm_FormClosing; + } + + private void LoginForm_FormClosing(object? sender, FormClosingEventArgs e) + { + Singleton.Instance.LoginResponsed -= LoginResponsed; + } + + private async void btnLogin_Click(object sender, EventArgs e) + { + string id = tbxId.Text; + string nickname = tbxNickname.Text; + if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(nickname)) { MessageBox.Show("Please input ID and Nickname."); return; } - Singleton.Instance.Id = tbxId.Text; - Singleton.Instance.Nickname = tbxNickname.Text; + await Singleton.Instance.ConnectAsync("127.0.0.1", 20000); - RoomListForm roomListForm = new RoomListForm(); - roomListForm.ShowDialog(); + Singleton.Instance.Id = id; + Singleton.Instance.Nickname = nickname; + + LoginRequestPacket packet = new LoginRequestPacket(id, nickname); + await Singleton.Instance.SendAsync(packet.Serialize(), SocketFlags.None); + } + + private void LoginResponsed(object? sender, EventArgs e) + { + if (sender == null) + return; + + LoginResponsePacket packet = (LoginResponsePacket)sender; + MessageBox.Show(packet.Code.ToString()); + if (packet.Code != StatusCode.Success) + { + RoomListForm roomListForm = new RoomListForm(); + roomListForm.ShowDialog(); + } + else + { + Singleton.Instance.Socket.Shutdown(SocketShutdown.Send); + } } } } \ No newline at end of file diff --git a/Chat/Client/Singleton.cs b/Chat/Client/Singleton.cs index 29d12b6..4b23440 100644 --- a/Chat/Client/Singleton.cs +++ b/Chat/Client/Singleton.cs @@ -1,6 +1,9 @@ -using System; +using Core; +using System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Sockets; using System.Text; using System.Threading.Tasks; @@ -12,5 +15,62 @@ namespace Client public string Id { get; set; } = ""; public string Nickname { get; set; } = ""; + public Socket Socket { get; } = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + public event EventHandler? LoginResponsed; + + public async Task ConnectAsync(string ip, int port) + { + IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port); + await this.Socket.ConnectAsync(endPoint); + ThreadPool.QueueUserWorkItem(ReceiveAsync, this.Socket); + } + + public async Task SendAsync(byte[] buffer, SocketFlags socketFlags) + { + return await this.Socket.SendAsync(buffer, socketFlags); + } + + private async void ReceiveAsync(object? sender) + { + if (sender == null) + return; + + Socket socket = (Socket)sender; + byte[] headerBuffer = new byte[2]; + while (true) + { + // header buffer + int n1 = await socket.ReceiveAsync(headerBuffer, SocketFlags.None); + if (n1 < 1) + { + Console.WriteLine($"[{DateTime.Now}] Disconnect server: {socket.RemoteEndPoint}"); + socket.Dispose(); + return; + } + else if (n1 == 1) + { + await socket.ReceiveAsync(new ArraySegment(headerBuffer, 1, 1), SocketFlags.None); + } + + // data buffer + short dataSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(headerBuffer)); + byte[] dataBuffer = new byte[dataSize]; + + int totalRecv = 0; + while (totalRecv < dataSize) + { + int n2 = await socket.ReceiveAsync(new ArraySegment(dataBuffer, totalRecv, dataSize - totalRecv), SocketFlags.None); + totalRecv += n2; + } + + PacketType packetType = (PacketType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(dataBuffer)); + if (packetType == PacketType.LoginResponse) + { + LoginResponsePacket packet = new LoginResponsePacket(dataBuffer); + LoginResponsed?.Invoke(packet, EventArgs.Empty); + } + } + } } } diff --git a/Chat/Core/IPacket.cs b/Chat/Core/IPacket.cs new file mode 100644 index 0000000..246b09a --- /dev/null +++ b/Chat/Core/IPacket.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + internal interface IPacket + { + byte[] Serialize(); + } +} diff --git a/Chat/Core/LoginRequestPacket.cs b/Chat/Core/LoginRequestPacket.cs new file mode 100644 index 0000000..dd72edf --- /dev/null +++ b/Chat/Core/LoginRequestPacket.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class LoginRequestPacket : IPacket + { + public string Id { get; private set; } + public string NickName { get; private set; } + + public LoginRequestPacket(string id, string nickname) + { + Id = id; + NickName = nickname; + } + + public LoginRequestPacket(byte[] buffer) + { + int cursor = 2; + + short idSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + cursor += sizeof(short); + + Id = Encoding.UTF8.GetString(buffer, cursor, idSize); + cursor += idSize; + + short nicknameSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + cursor += sizeof(short); + + NickName = Encoding.UTF8.GetString(buffer, cursor, nicknameSize); + } + + public byte[] Serialize() + { + // 2bytes header + // data: 2bytes packetType + 2bytes id size + id + 2bytes nickname size + nickname + + byte[] packetType = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)PacketType.LoginRequest)); + byte[] id = Encoding.UTF8.GetBytes(Id); + byte[] idSize = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)id.Length)); + byte[] nickname = Encoding.UTF8.GetBytes(NickName); + byte[] nicknameSize = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)nickname.Length)); + + short dataSize = (short)(packetType.Length + id.Length + idSize.Length + nickname.Length + nicknameSize.Length); + byte[] header = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(dataSize)); + + byte[] buffer = new byte[2 + dataSize]; + + int cursor = 0; + Array.Copy(header, 0, buffer, cursor, header.Length); + cursor += header.Length; + + Array.Copy(packetType, 0, buffer, cursor, packetType.Length); + cursor += packetType.Length; + + Array.Copy(idSize, 0, buffer, cursor, idSize.Length); + cursor += idSize.Length; + + Array.Copy(id, 0, buffer, cursor, id.Length); + cursor += id.Length; + + Array.Copy(nicknameSize, 0, buffer, cursor, nicknameSize.Length); + cursor += nicknameSize.Length; + + Array.Copy(nickname, 0, buffer, cursor, nickname.Length); + + return buffer; + } + } +} diff --git a/Chat/Core/LoginResponsePacket.cs b/Chat/Core/LoginResponsePacket.cs new file mode 100644 index 0000000..1997f74 --- /dev/null +++ b/Chat/Core/LoginResponsePacket.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class LoginResponsePacket : IPacket + { + public StatusCode Code { get; set; } + + public LoginResponsePacket(StatusCode code) + { + Code = code; + } + + public LoginResponsePacket(byte[] buffer) + { + Code = (StatusCode)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, 2)); + } + + public byte[] Serialize() + { + // 2bytes header + // data: 2bytes packetType + code + + byte[] packetType = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)PacketType.LoginResponse)); + byte[] code = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((int)Code)); + + short dataSize = (short)(packetType.Length + code.Length); + byte[] header = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(dataSize)); + + byte[] buffer = new byte[2 + dataSize]; + + int cursor = 0; + Array.Copy(header, 0, buffer, cursor, header.Length); + cursor += header.Length; + + Array.Copy(packetType, 0, buffer, cursor, packetType.Length); + cursor += packetType.Length; + + Array.Copy(code, 0, buffer, cursor, code.Length); + + return buffer; + } + } +} diff --git a/Chat/Core/PServer.cs b/Chat/Core/PServer.cs index 81b4cc1..480b4c7 100644 --- a/Chat/Core/PServer.cs +++ b/Chat/Core/PServer.cs @@ -62,7 +62,16 @@ namespace Core int n2 = await clientSocket.ReceiveAsync(new ArraySegment(dataBuffer, totalRecv, dataSize - totalRecv), SocketFlags.None); totalRecv += n2; } - Console.WriteLine($"[{DateTime.Now}] {clientSocket.RemoteEndPoint} client: {Encoding.UTF8.GetString(dataBuffer)}"); + + PacketType packetType = (PacketType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(dataBuffer)); + if (packetType == PacketType.LoginRequest) + { + LoginRequestPacket requestPacket = new LoginRequestPacket(dataBuffer); + Console.WriteLine($"Id: {requestPacket.Id}, Nickname: {requestPacket.NickName}"); + + LoginResponsePacket responsePacket = new LoginResponsePacket(StatusCode.Success); + await clientSocket.SendAsync(responsePacket.Serialize(), SocketFlags.None); + } } } } diff --git a/Chat/Core/PacketType.cs b/Chat/Core/PacketType.cs new file mode 100644 index 0000000..e280f6a --- /dev/null +++ b/Chat/Core/PacketType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public enum PacketType + { + LoginRequest, + LoginResponse, + } +} diff --git a/Chat/Core/StatusCode.cs b/Chat/Core/StatusCode.cs new file mode 100644 index 0000000..841828a --- /dev/null +++ b/Chat/Core/StatusCode.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public enum StatusCode + { + Success = 200, + } +}