From bf645548c5ba1235f16b421dba5ae9d7bab76937 Mon Sep 17 00:00:00 2001 From: syneffort Date: Tue, 10 Oct 2023 17:55:14 +0900 Subject: [PATCH] packet structure --- MySolution/STcpHelper/Packet/ISTcpPacket.cs | 13 +++++ MySolution/STcpHelper/Packet/PacketType.cs | 14 ++++++ MySolution/STcpHelper/Packet/SBufferHelper.cs | 27 +++++++++++ .../STcpHelper/Packet/STcpPacketHeader.cs | 42 ++++++++++++++++ .../STcpHelper/Packet/STcpTextPacket.cs | 40 ++++++++++++++++ MySolution/STcpHelper/STcpClient.cs | 44 +++++++++++++---- MySolution/STcpHelper/STcpHelper.csproj | 2 +- MySolution/STcpHelper/STcpServer.cs | 48 +++++++++++++++---- MySolution/SerialComApp/SerialCommApp.resx | 2 +- 9 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 MySolution/STcpHelper/Packet/ISTcpPacket.cs create mode 100644 MySolution/STcpHelper/Packet/PacketType.cs create mode 100644 MySolution/STcpHelper/Packet/SBufferHelper.cs create mode 100644 MySolution/STcpHelper/Packet/STcpPacketHeader.cs create mode 100644 MySolution/STcpHelper/Packet/STcpTextPacket.cs diff --git a/MySolution/STcpHelper/Packet/ISTcpPacket.cs b/MySolution/STcpHelper/Packet/ISTcpPacket.cs new file mode 100644 index 0000000..dc29f96 --- /dev/null +++ b/MySolution/STcpHelper/Packet/ISTcpPacket.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + public interface ISTcpPacket + { + byte[] Serialize(); + } +} diff --git a/MySolution/STcpHelper/Packet/PacketType.cs b/MySolution/STcpHelper/Packet/PacketType.cs new file mode 100644 index 0000000..163bd43 --- /dev/null +++ b/MySolution/STcpHelper/Packet/PacketType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + public enum PacketType + { + TEXT = 0, + + } +} diff --git a/MySolution/STcpHelper/Packet/SBufferHelper.cs b/MySolution/STcpHelper/Packet/SBufferHelper.cs new file mode 100644 index 0000000..875631b --- /dev/null +++ b/MySolution/STcpHelper/Packet/SBufferHelper.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + static class SBufferHelper + { + public static byte[] GetBuffer(int size, params byte[][] args) + { + byte[] bytes = new byte[size]; + int cursor = 0; + + for (int i = 0; i < args.Length; i++) + { + byte[] data = args[i]; + + Array.Copy(data, 0, bytes, cursor, data.Length); + cursor += data.Length; + } + + return bytes; + } + } +} diff --git a/MySolution/STcpHelper/Packet/STcpPacketHeader.cs b/MySolution/STcpHelper/Packet/STcpPacketHeader.cs new file mode 100644 index 0000000..4b7da66 --- /dev/null +++ b/MySolution/STcpHelper/Packet/STcpPacketHeader.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + /// + /// 4byte header + /// + public class STcpPacketHeader : ISTcpPacket + { + public PacketType Type { get; private set; } + public short DataLength { get; private set; } + + public STcpPacketHeader(PacketType type, int dataLength) + { + Type = type; + DataLength = (short)dataLength; + } + + public STcpPacketHeader(byte[] buffer) + { + int cursor = 0; + this.Type = (PacketType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + cursor += 2; + + this.DataLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + } + + // [2bytes Type][2bytes Size] + public byte[] Serialize() + { + byte[] type = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)this.Type)); + byte[] size = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(this.DataLength)); + + return SBufferHelper.GetBuffer(type.Length + size.Length, type, size); + } + } +} diff --git a/MySolution/STcpHelper/Packet/STcpTextPacket.cs b/MySolution/STcpHelper/Packet/STcpTextPacket.cs new file mode 100644 index 0000000..9faa8d7 --- /dev/null +++ b/MySolution/STcpHelper/Packet/STcpTextPacket.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + public class STcpTextPacket : ISTcpPacket + { + public string Text { get; private set; } + + public STcpTextPacket(string text) + { + this.Text = text; + } + + public STcpTextPacket(byte[] dataBuffer) + { + int cursor = 0; + short textSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(dataBuffer, cursor)); + cursor += sizeof(short); + + this.Text = Encoding.UTF8.GetString(dataBuffer, cursor, textSize); + } + + public byte[] Serialize() + { + byte[] text = Encoding.UTF8.GetBytes(Text); + byte[] textSize = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)text.Length)); + + // 4byte header + STcpPacketHeader header = new STcpPacketHeader(PacketType.TEXT, text.Length + textSize.Length); + + // [2bytes text size][n bytes text] + return SBufferHelper.GetBuffer(4 + textSize.Length + text.Length, header.Serialize(), textSize, text); + } + } +} diff --git a/MySolution/STcpHelper/STcpClient.cs b/MySolution/STcpHelper/STcpClient.cs index 5521427..fcb414e 100644 --- a/MySolution/STcpHelper/STcpClient.cs +++ b/MySolution/STcpHelper/STcpClient.cs @@ -1,5 +1,7 @@ -using System; +using STcpHelper.Packet; +using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net.Sockets; using System.Text; @@ -17,6 +19,9 @@ namespace STcpHelper private TcpClient _client; private NetworkStream _stream; + private readonly int HEADER_SIZE = 4; + private readonly int BUFFER_SIZE = 1024; + public async void Connect(string ip, int port) { try @@ -28,20 +33,35 @@ namespace STcpHelper _cts = new CancellationTokenSource(); _ = Task.Run(async () => { - byte[] readBuffer = new byte[1024]; + byte[] headerBuffer = new byte[HEADER_SIZE]; + byte[] dataBuffer = new byte[BUFFER_SIZE]; while (true) { Thread.Sleep(50); if (_cts.IsCancellationRequested) break; - int bytesRead = await this._stream.ReadAsync(readBuffer); - if (bytesRead < 1) - break; + int headerBytesRead = await _stream.ReadAsync(headerBuffer, 0, HEADER_SIZE); + if (headerBytesRead != 4) + { + WriteError(new Exception("Cannot read header")); + return; + } + + STcpPacketHeader header = new STcpPacketHeader(headerBuffer); + short dataSize = header.DataLength; + int totalRecv = 0; + while (totalRecv < dataSize) + { + int dataBytesRead = await _stream.ReadAsync(dataBuffer, totalRecv, dataSize - totalRecv); + totalRecv += dataBytesRead; + } - string message = Encoding.UTF8.GetString(readBuffer, 0, bytesRead); - if (this.MessageCallback != null) - this.MessageCallback(this, message); + if (header.Type == PacketType.TEXT) + { + STcpTextPacket packet = new STcpTextPacket(dataBuffer); + WriteMessage(packet.Text); + } } }, _cts.Token); } @@ -51,11 +71,17 @@ namespace STcpHelper } } + private byte[] MakeTextPacket(string text) + { + STcpTextPacket packet = new STcpTextPacket(text); + return packet.Serialize(); + } + public async void SendMessage(string message) { try { - byte[] sendBytes = Encoding.UTF8.GetBytes(message); + byte[] sendBytes = MakeTextPacket(message); await _stream.WriteAsync(sendBytes); } catch (Exception ex) diff --git a/MySolution/STcpHelper/STcpHelper.csproj b/MySolution/STcpHelper/STcpHelper.csproj index 132c02c..27ac386 100644 --- a/MySolution/STcpHelper/STcpHelper.csproj +++ b/MySolution/STcpHelper/STcpHelper.csproj @@ -1,4 +1,4 @@ - + net6.0 diff --git a/MySolution/STcpHelper/STcpServer.cs b/MySolution/STcpHelper/STcpServer.cs index dfbd447..0a794f6 100644 --- a/MySolution/STcpHelper/STcpServer.cs +++ b/MySolution/STcpHelper/STcpServer.cs @@ -1,4 +1,5 @@ -using System.Net; +using STcpHelper.Packet; +using System.Net; using System.Net.Sockets; using System.Text; @@ -10,6 +11,7 @@ namespace STcpHelper private List _clients; + private readonly int HEADER_SIZE = 4; private readonly int BUFFER_SIZE; private int _port; @@ -47,17 +49,37 @@ namespace STcpHelper { using (NetworkStream stream = client.GetStream()) { - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead; + byte[] headerBuffer = new byte[HEADER_SIZE]; + byte[] dataBuffer = new byte[BUFFER_SIZE]; try { - while ((bytesRead = await stream.ReadAsync(buffer, 0, BUFFER_SIZE)) > 0) + while (true) { - string message = Encoding.UTF8.GetString(buffer, 0, bytesRead); - WriteMessage($"[{client.Client.RemoteEndPoint.ToString()}] {message}"); - - // Broadcast - BroadcastMessage(message, client); + int headerBytesRead = await stream.ReadAsync(headerBuffer, 0, HEADER_SIZE); + if (headerBytesRead != 4) + { + WriteError(new Exception("Cannot read header")); + return; + } + + STcpPacketHeader header = new STcpPacketHeader(headerBuffer); + short dataSize = header.DataLength; + int totalRecv = 0; + while (totalRecv < dataSize) + { + int dataBytesRead = await stream.ReadAsync(dataBuffer, totalRecv, dataSize - totalRecv); + totalRecv += dataBytesRead; + } + + if (header.Type == PacketType.TEXT) + { + STcpTextPacket packet = new STcpTextPacket(dataBuffer); + WriteMessage($"[{client.Client.RemoteEndPoint.ToString()}] Type: {header.Type.ToString()}"); + + // Broadcast + BroadcastMessage(packet.Text, client); + + } if (!IsClientConnected(client)) break; @@ -81,9 +103,15 @@ namespace STcpHelper _cts.Cancel(); } + private byte[] MakeTextPacket(string text) + { + STcpTextPacket packet = new STcpTextPacket(text); + return packet.Serialize(); + } + private void BroadcastMessage(string message, TcpClient sender) { - byte[] resonseByte = Encoding.UTF8.GetBytes(message); + byte[] resonseByte = MakeTextPacket(message); foreach (TcpClient client in _clients) { if (client != sender && IsClientConnected(client)) diff --git a/MySolution/SerialComApp/SerialCommApp.resx b/MySolution/SerialComApp/SerialCommApp.resx index 6b10039..b432cfb 100644 --- a/MySolution/SerialComApp/SerialCommApp.resx +++ b/MySolution/SerialComApp/SerialCommApp.resx @@ -121,7 +121,7 @@ iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL - DwAACw8BkvkDpQAAAsBJREFUaEPt2cnLTXEcx/FrzJCphJ0F2diIbEQokWFnzhClyFB6yEJEyh+gUMaU + DgAACw4BQL7hQQAAAsBJREFUaEPt2cnLTXEcx/FrzJCphJ0F2diIbEQokWFnzhClyFB6yEJEyh+gUMaU WdlYWLBRiszjAmFjaUgZMvP+LE6dTp9z7jnnnt990PnUa/N07+/7u/ee3/g06tSpU+efzihswFncxzt8 x1e8xm0cx2oMx1+R7liOG/hdwC9cxXx0Q6dkNp7DdbCIh5iKtqUvjsF1piz9InvQE0EzDPfgOlGFKxiE IBmKZ3CF03zBt8TfmrmFAag0fXAXrmCcXrMd4zAYUYZgInbjCdx74y6h0sF9BK5QRANxJvKkKxaj2QSw