From a754ba29567d3586a02c6c1f80483f59cdcdfdb1 Mon Sep 17 00:00:00 2001 From: syneffort Date: Fri, 3 Mar 2023 09:44:36 +0900 Subject: [PATCH] user enter, leave --- Chat/Client/ChatRoomForm.Designer.cs | 1 + Chat/Client/ChatRoomForm.cs | 60 +++++++++++++++++++++++++++- Chat/Client/RoomListForm.cs | 8 ++-- Chat/Client/Singleton.cs | 12 ++++++ Chat/Core/PServer.cs | 42 ++++++++++++++++++- Chat/Core/UserEnterPacket.cs | 58 +++++++++++++++++++++++++++ Chat/Core/UserLeavePacket.cs | 58 +++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 Chat/Core/UserEnterPacket.cs create mode 100644 Chat/Core/UserLeavePacket.cs diff --git a/Chat/Client/ChatRoomForm.Designer.cs b/Chat/Client/ChatRoomForm.Designer.cs index 91e75fd..84652d9 100644 --- a/Chat/Client/ChatRoomForm.Designer.cs +++ b/Chat/Client/ChatRoomForm.Designer.cs @@ -84,6 +84,7 @@ this.Name = "ChatRoomForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "CharRoomForm"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ChatRoomForm_FormClosing); this.ResumeLayout(false); this.PerformLayout(); diff --git a/Chat/Client/ChatRoomForm.cs b/Chat/Client/ChatRoomForm.cs index 9074dd8..6aaa874 100644 --- a/Chat/Client/ChatRoomForm.cs +++ b/Chat/Client/ChatRoomForm.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; @@ -15,6 +17,14 @@ namespace Client public ChatRoomForm() { InitializeComponent(); + InitInstance(); + } + + private void InitInstance() + { + lbxUser.Items.Add(Singleton.Instance.Nickname); + Singleton.Instance.UserEnterResponsed += UserEnterResponsed; + Singleton.Instance.UserLeaveResponsed += UserLeaveResponsed; } private void btmSend_Click(object sender, EventArgs e) @@ -33,5 +43,53 @@ namespace Client lbxMsg.SelectedIndex = lbxMsg.Items.Count - 1; lbxMsg.SelectedIndex = -1; } + + private void InvokeMethod(InvokedMethod method) + { + if (this.InvokeRequired) + { + this.Invoke(new MethodInvoker(() => + { + method(); + })); + } + else + { + method(); + } + } + + private void UserEnterResponsed(object? sender, EventArgs e) + { + if (sender == null) + return; + + UserEnterPacket packet = (UserEnterPacket)sender; + InvokeMethod(() => + { + lbxUser.Items.Add(packet.Nickname); + }); + } + + private void UserLeaveResponsed(object? sender, EventArgs e) + { + if (sender == null) + return; + + UserLeavePacket packet = (UserLeavePacket)sender; + InvokeMethod(() => + { + lbxUser.Items.Remove(packet.Nickname); + }); + } + + private async void ChatRoomForm_FormClosing(object sender, FormClosingEventArgs e) + { + Singleton.Instance.UserEnterResponsed -= UserEnterResponsed; + Singleton.Instance.UserLeaveResponsed -= UserLeaveResponsed; + + UserLeavePacket packet = new UserLeavePacket(Singleton.Instance.Nickname); + await Singleton.Instance.SendAsync(packet.Serialize(), SocketFlags.None); + } } } diff --git a/Chat/Client/RoomListForm.cs b/Chat/Client/RoomListForm.cs index e10874e..90bd72c 100644 --- a/Chat/Client/RoomListForm.cs +++ b/Chat/Client/RoomListForm.cs @@ -12,10 +12,10 @@ using System.Windows.Forms; namespace Client { + delegate void InvokedMethod(); + public partial class RoomListForm : Form { - private delegate void InvokedMethod(); - public RoomListForm() { InitializeComponent(); @@ -61,9 +61,9 @@ namespace Client private void InvokeMethod(InvokedMethod method) { - if (InvokeRequired) + if (this.InvokeRequired) { - lbxRoom.Invoke(new MethodInvoker(() => + this.Invoke(new MethodInvoker(() => { method(); })); diff --git a/Chat/Client/Singleton.cs b/Chat/Client/Singleton.cs index b7b511b..40a1957 100644 --- a/Chat/Client/Singleton.cs +++ b/Chat/Client/Singleton.cs @@ -21,6 +21,8 @@ namespace Client public event EventHandler? CreateRoomResponsed; public event EventHandler? RoomListResponsed; public event EventHandler? EnterRoomResponsed; + public event EventHandler? UserEnterResponsed; + public event EventHandler? UserLeaveResponsed; public async Task ConnectAsync(string ip, int port) { @@ -88,6 +90,16 @@ namespace Client EnterRoomResponsePacket packet = new EnterRoomResponsePacket(dataBuffer); EnterRoomResponsed?.Invoke(packet, EventArgs.Empty); } + else if (packetType == PacketType.UserEnter) + { + UserEnterPacket packet = new UserEnterPacket(dataBuffer); + UserEnterResponsed?.Invoke(packet, EventArgs.Empty); + } + else if (packetType == PacketType.UserLeave) + { + UserLeavePacket packet = new UserLeavePacket(dataBuffer); + UserLeaveResponsed?.Invoke(packet, EventArgs.Empty); + } } } } diff --git a/Chat/Core/PServer.cs b/Chat/Core/PServer.cs index 1b7a2f9..1accb62 100644 --- a/Chat/Core/PServer.cs +++ b/Chat/Core/PServer.cs @@ -13,7 +13,8 @@ namespace Core { private Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - private ConcurrentDictionary Rooms { get; } = new ConcurrentDictionary(); + public ConcurrentDictionary Rooms { get; } = new ConcurrentDictionary(); + public ConcurrentDictionary Clients { get; } = new ConcurrentDictionary(); public PServer(string ip, int port, int backlog) { @@ -74,6 +75,8 @@ namespace Core if (packetType == PacketType.LoginRequest) { LoginRequestPacket requestPacket = new LoginRequestPacket(dataBuffer); + + Clients.TryAdd(requestPacket.Id, clientSocket); Console.WriteLine($"[{DateTime.Now}] LoginRequest - Id: {requestPacket.Id}, Nickname: {requestPacket.NickName}"); id = requestPacket.Id; @@ -119,6 +122,24 @@ namespace Core EnterRoomResponsePacket responsePacket = new EnterRoomResponsePacket(StatusCode.Success); await clientSocket.SendAsync(responsePacket.Serialize(), SocketFlags.None); + + await Task.Delay(100); + foreach (var user in room.Users) + { + if (user.Value == nickname) + continue; + + // add me to other user + if (Clients.TryGetValue(user.Key, out var otherClient)) + { + UserEnterPacket enterPacket = new UserEnterPacket(nickname); + await otherClient.SendAsync(enterPacket.Serialize(), SocketFlags.None); + } + + // add other user to me + UserEnterPacket packet = new UserEnterPacket(user.Value); + await clientSocket.SendAsync(packet.Serialize(), SocketFlags.None); + } } else { @@ -129,6 +150,25 @@ namespace Core } } + else if (packetType == PacketType.UserLeave) + { + UserLeavePacket packet = new UserLeavePacket(dataBuffer); + if (Rooms.TryGetValue(roomName, out var room)) + { + room.Users.TryRemove(id, out _); + + if (room.Users.IsEmpty) + Rooms.TryRemove(roomName, out _); + + roomName = ""; + + foreach (var user in room.Users) + { + if (Clients.TryGetValue(user.Key, out var otherClient)) + await otherClient.SendAsync(packet.Serialize(), SocketFlags.None); + } + } + } } } } diff --git a/Chat/Core/UserEnterPacket.cs b/Chat/Core/UserEnterPacket.cs new file mode 100644 index 0000000..d45ed8b --- /dev/null +++ b/Chat/Core/UserEnterPacket.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 UserEnterPacket : IPacket + { + public string Nickname { get; private set; } + + public UserEnterPacket(string nickname) + { + Nickname = nickname; + } + + public UserEnterPacket(byte[] buffer) + { + int cursor = 2; + + 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.UserEnter)); + byte[] roomName = Encoding.UTF8.GetBytes(Nickname); + 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/UserLeavePacket.cs b/Chat/Core/UserLeavePacket.cs new file mode 100644 index 0000000..b8a41c9 --- /dev/null +++ b/Chat/Core/UserLeavePacket.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 UserLeavePacket : IPacket + { + public string Nickname { get; private set; } + + public UserLeavePacket(string nickname) + { + Nickname = nickname; + } + + public UserLeavePacket(byte[] buffer) + { + int cursor = 2; + + 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.UserLeave)); + byte[] roomName = Encoding.UTF8.GetBytes(Nickname); + 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; + } + } +}