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,
+ }
+}