From 09cce59aa2978de7c96a4431ef780054368da9e5 Mon Sep 17 00:00:00 2001 From: syneffort Date: Fri, 10 Feb 2023 17:55:09 +0900 Subject: [PATCH] create room, get room information from server --- Chat/Client/LoginForm.cs | 12 ++- Chat/Client/RoomListForm.Designer.cs | 20 ++++- Chat/Client/RoomListForm.cs | 101 ++++++++++++++++++++++++-- Chat/Client/Singleton.cs | 12 +++ Chat/Core/CreateRoomRequestPacket.cs | 58 +++++++++++++++ Chat/Core/CreateRoomResponsePacket.cs | 49 +++++++++++++ Chat/Core/PServer.cs | 42 ++++++++++- Chat/Core/PacketType.cs | 4 + Chat/Core/Room.cs | 14 ++++ Chat/Core/RoomListRequestPacket.cs | 30 ++++++++ Chat/Core/RoomListResponsePacket.cs | 68 +++++++++++++++++ Chat/Core/StatusCode.cs | 1 + 12 files changed, 393 insertions(+), 18 deletions(-) create mode 100644 Chat/Core/CreateRoomRequestPacket.cs create mode 100644 Chat/Core/CreateRoomResponsePacket.cs create mode 100644 Chat/Core/Room.cs create mode 100644 Chat/Core/RoomListRequestPacket.cs create mode 100644 Chat/Core/RoomListResponsePacket.cs diff --git a/Chat/Client/LoginForm.cs b/Chat/Client/LoginForm.cs index 5fb1992..1712592 100644 --- a/Chat/Client/LoginForm.cs +++ b/Chat/Client/LoginForm.cs @@ -47,11 +47,15 @@ namespace Client return; LoginResponsePacket packet = (LoginResponsePacket)sender; - MessageBox.Show(packet.Code.ToString()); - if (packet.Code != StatusCode.Success) + if (packet.Code == StatusCode.Success) { - RoomListForm roomListForm = new RoomListForm(); - roomListForm.ShowDialog(); + IAsyncResult ar = null; + ar = BeginInvoke(() => + { + RoomListForm roomListForm = new RoomListForm(); + roomListForm.ShowDialog(); + EndInvoke(ar); + }); } else { diff --git a/Chat/Client/RoomListForm.Designer.cs b/Chat/Client/RoomListForm.Designer.cs index e61e0a3..c2e155d 100644 --- a/Chat/Client/RoomListForm.Designer.cs +++ b/Chat/Client/RoomListForm.Designer.cs @@ -34,20 +34,21 @@ this.btnCreate = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); + this.btnRefresh = new System.Windows.Forms.Button(); this.SuspendLayout(); // // lbxRoom // this.lbxRoom.FormattingEnabled = true; this.lbxRoom.ItemHeight = 15; - this.lbxRoom.Location = new System.Drawing.Point(12, 27); + this.lbxRoom.Location = new System.Drawing.Point(12, 31); this.lbxRoom.Name = "lbxRoom"; this.lbxRoom.Size = new System.Drawing.Size(180, 214); this.lbxRoom.TabIndex = 0; // // btnEnter // - this.btnEnter.Location = new System.Drawing.Point(12, 247); + this.btnEnter.Location = new System.Drawing.Point(12, 251); this.btnEnter.Name = "btnEnter"; this.btnEnter.Size = new System.Drawing.Size(180, 23); this.btnEnter.TabIndex = 1; @@ -75,7 +76,7 @@ // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Location = new System.Drawing.Point(12, 13); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(59, 15); this.label1.TabIndex = 4; @@ -90,6 +91,16 @@ this.label2.TabIndex = 5; this.label2.Text = "Creation"; // + // btnRefresh + // + this.btnRefresh.Location = new System.Drawing.Point(134, 5); + this.btnRefresh.Name = "btnRefresh"; + this.btnRefresh.Size = new System.Drawing.Size(58, 23); + this.btnRefresh.TabIndex = 1; + this.btnRefresh.Text = "Refresh"; + this.btnRefresh.UseVisualStyleBackColor = true; + this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click); + // // RoomListForm // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -99,6 +110,7 @@ this.Controls.Add(this.label1); this.Controls.Add(this.btnCreate); this.Controls.Add(this.tbxRoomName); + this.Controls.Add(this.btnRefresh); this.Controls.Add(this.btnEnter); this.Controls.Add(this.lbxRoom); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; @@ -108,6 +120,7 @@ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Room list"; this.Activated += new System.EventHandler(this.RoomListForm_Activated); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.RoomListForm_FormClosing); this.ResumeLayout(false); this.PerformLayout(); @@ -121,5 +134,6 @@ private Button btnCreate; private Label label1; private Label label2; + private Button btnRefresh; } } \ No newline at end of file diff --git a/Chat/Client/RoomListForm.cs b/Chat/Client/RoomListForm.cs index 02cd168..3017895 100644 --- a/Chat/Client/RoomListForm.cs +++ b/Chat/Client/RoomListForm.cs @@ -1,9 +1,11 @@ -using System; +using Core; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; +using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; @@ -12,9 +14,18 @@ namespace Client { public partial class RoomListForm : Form { + private delegate void InvokedMethod(); + public RoomListForm() { InitializeComponent(); + InitInstance(); + } + + private void InitInstance() + { + Singleton.Instance.CreateRoomResponsed += CreateRoomResponsed; + Singleton.Instance.RoomListResponsed += Instance_RoomListResponsed; } private void btnEnter_Click(object sender, EventArgs e) @@ -25,12 +36,17 @@ namespace Client return; } - ChatRoomForm chatRoomForm = new ChatRoomForm(); - chatRoomForm.Text = lbxRoom.SelectedItem.ToString(); - chatRoomForm.ShowDialog(); + IAsyncResult ar = null; + ar = BeginInvoke(() => + { + ChatRoomForm chatRoomForm = new ChatRoomForm(); + chatRoomForm.Text = lbxRoom.SelectedItem.ToString(); + chatRoomForm.ShowDialog(); + EndInvoke(ar); + }); } - private void btnCreate_Click(object sender, EventArgs e) + private async void btnCreate_Click(object sender, EventArgs e) { string roomName = tbxRoomName.Text; if (string.IsNullOrEmpty(roomName)) @@ -39,14 +55,83 @@ namespace Client return; } - ChatRoomForm chatRoomForm = new ChatRoomForm(); - chatRoomForm.Text = roomName; - chatRoomForm.ShowDialog(); + CreateRoomRequestPacket packet = new CreateRoomRequestPacket(roomName); + await Singleton.Instance.SendAsync(packet.Serialize(), SocketFlags.None); } private void RoomListForm_Activated(object sender, EventArgs e) + { + btnRefresh_Click(sender, e); + } + + private void InvokeMethod(InvokedMethod method) + { + if (InvokeRequired) + { + lbxRoom.Invoke(new MethodInvoker(() => + { + method(); + })); + } + else + { + method(); + } + } + + private void CreateRoomResponsed(object? sender, EventArgs e) + { + if (sender == null) + return; + + CreateRoomResponsePacket packet = (CreateRoomResponsePacket)sender; + if (packet.Code == StatusCode.Success) + { + string roomName = tbxRoomName.Text; + InvokeMethod(() => + { + lbxRoom.Items.Add(roomName); + tbxRoomName.Text = ""; + }); + + IAsyncResult ar = null; + ar = BeginInvoke(() => + { + ChatRoomForm chatRoomForm = new ChatRoomForm(); + chatRoomForm.Text = roomName; + chatRoomForm.ShowDialog(); + EndInvoke(ar); + }); + } + } + + private void Instance_RoomListResponsed(object? sender, EventArgs e) + { + if (sender == null) + return; + + RoomListResponsePacket packet = (RoomListResponsePacket)sender; + InvokeMethod(() => + { + foreach (string item in packet.RoomNames) + { + lbxRoom.Items.Add(item); + } + }); + } + + private async void btnRefresh_Click(object sender, EventArgs e) { lbxRoom.Items.Clear(); + RoomListRequestPacket packet = new RoomListRequestPacket(); + await Singleton.Instance.SendAsync(packet.Serialize(), SocketFlags.None); + } + + private void RoomListForm_FormClosing(object sender, FormClosingEventArgs e) + { + Singleton.Instance.CreateRoomResponsed -= CreateRoomResponsed; + Singleton.Instance.RoomListResponsed -= Instance_RoomListResponsed; + Singleton.Instance.Socket.Shutdown(SocketShutdown.Send); } } } diff --git a/Chat/Client/Singleton.cs b/Chat/Client/Singleton.cs index 4b23440..707202b 100644 --- a/Chat/Client/Singleton.cs +++ b/Chat/Client/Singleton.cs @@ -18,6 +18,8 @@ namespace Client public Socket Socket { get; } = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); public event EventHandler? LoginResponsed; + public event EventHandler? CreateRoomResponsed; + public event EventHandler? RoomListResponsed; public async Task ConnectAsync(string ip, int port) { @@ -70,6 +72,16 @@ namespace Client LoginResponsePacket packet = new LoginResponsePacket(dataBuffer); LoginResponsed?.Invoke(packet, EventArgs.Empty); } + else if (packetType == PacketType.CreateRoomResponse) + { + CreateRoomResponsePacket packet = new CreateRoomResponsePacket(dataBuffer); + CreateRoomResponsed?.Invoke(packet, EventArgs.Empty); + } + else if (packetType == PacketType.RoomListResponse) + { + RoomListResponsePacket packet = new RoomListResponsePacket(dataBuffer); + RoomListResponsed?.Invoke(packet, EventArgs.Empty); + } } } } diff --git a/Chat/Core/CreateRoomRequestPacket.cs b/Chat/Core/CreateRoomRequestPacket.cs new file mode 100644 index 0000000..80ba6b0 --- /dev/null +++ b/Chat/Core/CreateRoomRequestPacket.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class CreateRoomRequestPacket : IPacket + { + public string RoomName { get; private set; } + + public CreateRoomRequestPacket(string roomName) + { + RoomName = roomName; + } + + public CreateRoomRequestPacket(byte[] buffer) + { + int cursor = 2; + + short roomNameSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + cursor += sizeof(short); + + RoomName = Encoding.UTF8.GetString(buffer, cursor, roomNameSize); + } + + public byte[] Serialize() + { + // 2bytes header + // data: 2bytes packetType + 2bytes id size + id + 2bytes nickname size + nickname + + byte[] packetType = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)PacketType.CreateRoomRequest)); + byte[] roomName = Encoding.UTF8.GetBytes(RoomName); + byte[] roomNameSize = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)roomName.Length)); + + short dataSize = (short)(packetType.Length + roomName.Length + roomNameSize.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(roomNameSize, 0, buffer, cursor, roomNameSize.Length); + cursor += roomNameSize.Length; + + Array.Copy(roomName, 0, buffer, cursor, roomName.Length); + + return buffer; + } + } +} diff --git a/Chat/Core/CreateRoomResponsePacket.cs b/Chat/Core/CreateRoomResponsePacket.cs new file mode 100644 index 0000000..87b453a --- /dev/null +++ b/Chat/Core/CreateRoomResponsePacket.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 CreateRoomResponsePacket : IPacket + { + public StatusCode Code { get; set; } + + public CreateRoomResponsePacket(StatusCode code) + { + Code = code; + } + + public CreateRoomResponsePacket(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.CreateRoomResponse)); + 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 480b4c7..caa87b1 100644 --- a/Chat/Core/PServer.cs +++ b/Chat/Core/PServer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; @@ -11,7 +12,9 @@ namespace Core public class PServer { private Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - + + private ConcurrentDictionary Rooms { get; } = new ConcurrentDictionary(); + public PServer(string ip, int port, int backlog) { IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port); @@ -37,13 +40,17 @@ namespace Core Socket clientSocket = (Socket)sender; byte[] headerBuffer = new byte[2]; + string id = ""; + string nickname = ""; + string roomName = ""; + while (true) { // header buffer int n1 = await clientSocket.ReceiveAsync(headerBuffer, SocketFlags.None); if (n1 < 1) { - Console.WriteLine($"[{DateTime.Now}] Disconnect client: {clientSocket.RemoteEndPoint}"); + Console.WriteLine($"[{DateTime.Now}] Disconnect client - {clientSocket.RemoteEndPoint}"); clientSocket.Dispose(); return; } @@ -67,11 +74,40 @@ namespace Core if (packetType == PacketType.LoginRequest) { LoginRequestPacket requestPacket = new LoginRequestPacket(dataBuffer); - Console.WriteLine($"Id: {requestPacket.Id}, Nickname: {requestPacket.NickName}"); + Console.WriteLine($"[{DateTime.Now}] LoginRequest - Id: {requestPacket.Id}, Nickname: {requestPacket.NickName}"); + + id = requestPacket.Id; + nickname = requestPacket.NickName; LoginResponsePacket responsePacket = new LoginResponsePacket(StatusCode.Success); await clientSocket.SendAsync(responsePacket.Serialize(), SocketFlags.None); } + else if (packetType == PacketType.CreateRoomRequest) + { + CreateRoomRequestPacket requestPacket = new CreateRoomRequestPacket(dataBuffer); + Room room = new Room(); + if (Rooms.TryAdd(requestPacket.RoomName, room)) + { + roomName = requestPacket.RoomName; + room.Users.TryAdd(id, nickname); + Console.WriteLine($"[{DateTime.Now}] CreateRoomRequest - RoomName: {roomName}"); + + CreateRoomResponsePacket responsePacket = new CreateRoomResponsePacket(StatusCode.Success); + await clientSocket.SendAsync(responsePacket.Serialize(), SocketFlags.None); + } + else + { + Console.WriteLine($"[{DateTime.Now}] CreateRoomRequest failed - RoomName: {requestPacket.RoomName}"); + + CreateRoomResponsePacket responsePacket = new CreateRoomResponsePacket(StatusCode.Failed); + await clientSocket.SendAsync(responsePacket.Serialize(), SocketFlags.None); + } + } + else if (packetType == PacketType.RoomListRequest) + { + RoomListResponsePacket packet = new RoomListResponsePacket(Rooms.Keys); + await clientSocket.SendAsync(packet.Serialize(), SocketFlags.None); + } } } } diff --git a/Chat/Core/PacketType.cs b/Chat/Core/PacketType.cs index e280f6a..8911fc5 100644 --- a/Chat/Core/PacketType.cs +++ b/Chat/Core/PacketType.cs @@ -10,5 +10,9 @@ namespace Core { LoginRequest, LoginResponse, + CreateRoomRequest, + CreateRoomResponse, + RoomListRequest, + RoomListResponse, } } diff --git a/Chat/Core/Room.cs b/Chat/Core/Room.cs new file mode 100644 index 0000000..1250e9f --- /dev/null +++ b/Chat/Core/Room.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class Room + { + public ConcurrentDictionary Users { get; } = new ConcurrentDictionary(); + } +} diff --git a/Chat/Core/RoomListRequestPacket.cs b/Chat/Core/RoomListRequestPacket.cs new file mode 100644 index 0000000..a8b45ff --- /dev/null +++ b/Chat/Core/RoomListRequestPacket.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class RoomListRequestPacket : IPacket + { + public byte[] Serialize() + { + byte[] packetType = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)PacketType.RoomListRequest)); + + short dataSize = (short)(packetType.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); + + return buffer; + } + } +} diff --git a/Chat/Core/RoomListResponsePacket.cs b/Chat/Core/RoomListResponsePacket.cs new file mode 100644 index 0000000..2fa038c --- /dev/null +++ b/Chat/Core/RoomListResponsePacket.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class RoomListResponsePacket : IPacket + { + public List RoomNames { get; } + + public RoomListResponsePacket(ICollection roomNames) + { + RoomNames = new List(roomNames); + } + + public RoomListResponsePacket(byte[] buffer) + { + RoomNames = new List(); + for (int cursor = 2; cursor < buffer.Length;) + { + short roomNameSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + cursor += sizeof(short); + + RoomNames.Add(Encoding.UTF8.GetString(buffer, cursor, roomNameSize)); + cursor += roomNameSize; + } + } + + public byte[] Serialize() + { + byte[] packetType = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)PacketType.RoomListResponse)); + + short dataSize = (short)(packetType.Length); + + List temp = new List(); + foreach (string item in RoomNames) + { + byte[] nameBuffer = Encoding.UTF8.GetBytes(item); + byte[] nameSize = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)nameBuffer.Length)); + dataSize += (short)(nameBuffer.Length + nameSize.Length); + temp.Add(nameSize); + temp.Add(nameBuffer); + } + + 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; + + foreach (byte[] item in temp) + { + Array.Copy(item, 0, buffer, cursor, item.Length); + cursor += item.Length; + } + + return buffer; + } + } +} diff --git a/Chat/Core/StatusCode.cs b/Chat/Core/StatusCode.cs index 841828a..d8b3c66 100644 --- a/Chat/Core/StatusCode.cs +++ b/Chat/Core/StatusCode.cs @@ -9,5 +9,6 @@ namespace Core public enum StatusCode { Success = 200, + Failed = 500, } }