From 044ace6552e6532ccaecf4b10d246e4011df3014 Mon Sep 17 00:00:00 2001 From: syneffort Date: Thu, 12 Oct 2023 16:21:04 +0900 Subject: [PATCH] refactoring, file packet --- .../STcpHelper/Packet/ISTcpAsyncPacket.cs | 13 ++++ MySolution/STcpHelper/Packet/PacketType.cs | 2 + MySolution/STcpHelper/Packet/SBufferHelper.cs | 16 +++++ .../Packet/STcpClientListReqPacket.cs | 4 +- .../Packet/STcpClientListResPacket.cs | 14 ++-- .../STcpHelper/Packet/STcpFileReqPacket.cs | 41 ++++++++++++ .../STcpHelper/Packet/STcpFileResPacket.cs | 67 +++++++++++++++++++ .../STcpHelper/Packet/STcpPacketHeader.cs | 32 ++++++--- .../STcpHelper/Packet/STcpTextPacket.cs | 15 +++-- MySolution/STcpHelper/STcpClient.cs | 33 +++++++-- MySolution/STcpHelper/STcpServer.cs | 38 +++++++++-- MySolution/SerialComApp/SerialCommApp.resx | 2 +- MySolution/TAPClient/Program.cs | 7 ++ 13 files changed, 247 insertions(+), 37 deletions(-) create mode 100644 MySolution/STcpHelper/Packet/ISTcpAsyncPacket.cs create mode 100644 MySolution/STcpHelper/Packet/STcpFileReqPacket.cs create mode 100644 MySolution/STcpHelper/Packet/STcpFileResPacket.cs diff --git a/MySolution/STcpHelper/Packet/ISTcpAsyncPacket.cs b/MySolution/STcpHelper/Packet/ISTcpAsyncPacket.cs new file mode 100644 index 0000000..88adbbb --- /dev/null +++ b/MySolution/STcpHelper/Packet/ISTcpAsyncPacket.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 ISTcpAsyncPacket + { + Task Serialize(); + } +} diff --git a/MySolution/STcpHelper/Packet/PacketType.cs b/MySolution/STcpHelper/Packet/PacketType.cs index 709510b..720b1b6 100644 --- a/MySolution/STcpHelper/Packet/PacketType.cs +++ b/MySolution/STcpHelper/Packet/PacketType.cs @@ -11,5 +11,7 @@ namespace STcpHelper.Packet TEXT = 0, REQ_CLIENT_LIST, RES_CLIENT_LIST, + REQ_FILE, + RES_FILE, } } diff --git a/MySolution/STcpHelper/Packet/SBufferHelper.cs b/MySolution/STcpHelper/Packet/SBufferHelper.cs index 9c9c7a3..39d8b01 100644 --- a/MySolution/STcpHelper/Packet/SBufferHelper.cs +++ b/MySolution/STcpHelper/Packet/SBufferHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; @@ -23,5 +24,20 @@ namespace STcpHelper.Packet return bytes; } + + public static byte[] ConvertPacketTypeToBuffer(PacketType packetType) + { + return BitConverter.GetBytes(IPAddress.HostToNetworkOrder((int)packetType)); + } + + public static byte[] ConvertDataLengthToBuffer(int dataLength) + { + return BitConverter.GetBytes(IPAddress.HostToNetworkOrder(dataLength)); + } + + public static int ConvertBufferToDataLength(byte[] dataBuffer, int cursor) + { + return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(dataBuffer, cursor)); + } } } diff --git a/MySolution/STcpHelper/Packet/STcpClientListReqPacket.cs b/MySolution/STcpHelper/Packet/STcpClientListReqPacket.cs index 1344564..038b44c 100644 --- a/MySolution/STcpHelper/Packet/STcpClientListReqPacket.cs +++ b/MySolution/STcpHelper/Packet/STcpClientListReqPacket.cs @@ -15,11 +15,9 @@ namespace STcpHelper.Packet public byte[] Serialize() { - // 4bytes header STcpPacketHeader header = new STcpPacketHeader(PacketType.REQ_CLIENT_LIST, 0); - // [header] - return SBufferHelper.GetBuffer(4, header.Serialize()); + return SBufferHelper.GetBuffer(STcpPacketHeader.HEADER_LENGTH, header.Serialize()); } } } diff --git a/MySolution/STcpHelper/Packet/STcpClientListResPacket.cs b/MySolution/STcpHelper/Packet/STcpClientListResPacket.cs index 674a105..475508b 100644 --- a/MySolution/STcpHelper/Packet/STcpClientListResPacket.cs +++ b/MySolution/STcpHelper/Packet/STcpClientListResPacket.cs @@ -26,8 +26,8 @@ namespace STcpHelper.Packet public STcpClientListResPacket(byte[] dataBuffer) { int cursor = 0; - short length = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(dataBuffer, cursor)); - cursor += sizeof(short); + int length = SBufferHelper.ConvertBufferToDataLength(dataBuffer, cursor); + cursor += sizeof(int); string jsonString = SEncoding.GetString(dataBuffer, cursor, length); List clients = JsonSerializer.Deserialize>(jsonString); @@ -39,13 +39,13 @@ namespace STcpHelper.Packet { string jsonString = JsonSerializer.Serialize(this.Clients); byte[] data = SEncoding.GetBytes(jsonString); - byte[] dataLength = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)data.Length)); + byte[] dataLength = SBufferHelper.ConvertDataLengthToBuffer(data.Length); - // 4bytes header - STcpPacketHeader header = new STcpPacketHeader(PacketType.RES_CLIENT_LIST, dataLength.Length + data.Length); + int dataSize = STcpPacketHeader.GetDataSize(data, dataLength); - // [header][2bytes size][n bytes string] - return SBufferHelper.GetBuffer(4 + dataLength.Length + data.Length, header.Serialize(), dataLength, data); + STcpPacketHeader header = new STcpPacketHeader(PacketType.RES_CLIENT_LIST, dataSize); + + return SBufferHelper.GetBuffer(STcpPacketHeader.HEADER_LENGTH + dataSize, header.Serialize(), dataLength, data); } } } diff --git a/MySolution/STcpHelper/Packet/STcpFileReqPacket.cs b/MySolution/STcpHelper/Packet/STcpFileReqPacket.cs new file mode 100644 index 0000000..208f10b --- /dev/null +++ b/MySolution/STcpHelper/Packet/STcpFileReqPacket.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + public class STcpFileReqPacket : ISTcpPacket + { + public string Path { get; private set; } + + public STcpFileReqPacket(string path) + { + this.Path = path; + } + + public STcpFileReqPacket(byte[] dataBuffer) + { + int cursor = 0; + int length = SBufferHelper.ConvertBufferToDataLength(dataBuffer, cursor); + cursor += sizeof(int); + + this.Path = SEncoding.GetString(dataBuffer, cursor, length); + } + + public byte[] Serialize() + { + byte[] data = SEncoding.GetBytes(this.Path); + byte[] dataLength = SBufferHelper.ConvertDataLengthToBuffer(data.Length); + + int dataSize = STcpPacketHeader.GetDataSize(data, dataLength); + + STcpPacketHeader header = new STcpPacketHeader(PacketType.REQ_FILE, dataSize); + + return SBufferHelper.GetBuffer(STcpPacketHeader.HEADER_LENGTH + dataSize, header.Serialize(), dataLength, data); + } + } +} diff --git a/MySolution/STcpHelper/Packet/STcpFileResPacket.cs b/MySolution/STcpHelper/Packet/STcpFileResPacket.cs new file mode 100644 index 0000000..9761e45 --- /dev/null +++ b/MySolution/STcpHelper/Packet/STcpFileResPacket.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace STcpHelper.Packet +{ + public class STcpFileResPacket : ISTcpAsyncPacket + { + private string _path; + + public string FileName { get; private set; } + public byte[] FileBinary { get; private set; } + + public STcpFileResPacket(string path) + { + this.FileName = Path.GetFileName(path); + _path = path; + } + + public STcpFileResPacket(byte[] dataBuffer, string path) + { + int cursor = 0; + int nameLength = SBufferHelper.ConvertBufferToDataLength(dataBuffer, cursor); + cursor += sizeof(int); + + this.FileName = SEncoding.GetString(dataBuffer, cursor, nameLength); + cursor += nameLength; + + int fileSize = SBufferHelper.ConvertBufferToDataLength(dataBuffer, cursor); + cursor += sizeof(int); + + this.FileBinary = new byte[fileSize]; + Array.Copy(dataBuffer, cursor, this.FileBinary, 0, fileSize); + + File.WriteAllBytes(path + @$"\{FileName}", this.FileBinary); + } + + public async Task Serialize() + { + byte[] name = SEncoding.GetBytes(this.FileName); + byte[] nameLength = SBufferHelper.ConvertDataLengthToBuffer(name.Length); + byte[] data = await ReadFileAsync(_path); + byte[] dataLength = SBufferHelper.ConvertDataLengthToBuffer(data.Length); + + int dataSize = STcpPacketHeader.GetDataSize(name, nameLength, data, dataLength); + + // 4bytes header + STcpPacketHeader header = new STcpPacketHeader(PacketType.RES_FILE, dataSize); + + // [heaer][2byte name size][n bytes name][2bytes file size][n bytes string] + return SBufferHelper.GetBuffer(STcpPacketHeader.HEADER_LENGTH + dataSize, header.Serialize(), nameLength, name, dataLength, data); + } + + private async Task ReadFileAsync(string path) + { + using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1024, useAsync: true)) + { + byte[] buffer = new byte[stream.Length]; + await stream.ReadAsync(buffer, 0, (int)stream.Length); + return buffer; + } + } + } +} diff --git a/MySolution/STcpHelper/Packet/STcpPacketHeader.cs b/MySolution/STcpHelper/Packet/STcpPacketHeader.cs index 4b7da66..87fe799 100644 --- a/MySolution/STcpHelper/Packet/STcpPacketHeader.cs +++ b/MySolution/STcpHelper/Packet/STcpPacketHeader.cs @@ -12,31 +12,45 @@ namespace STcpHelper.Packet /// public class STcpPacketHeader : ISTcpPacket { + private readonly int TYPE_LENGTH = 4; + public static readonly int HEADER_LENGTH = 8; + public PacketType Type { get; private set; } - public short DataLength { get; private set; } + public int DataLength { get; private set; } public STcpPacketHeader(PacketType type, int dataLength) { Type = type; - DataLength = (short)dataLength; + DataLength = dataLength; } public STcpPacketHeader(byte[] buffer) { int cursor = 0; - this.Type = (PacketType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); - cursor += 2; + this.Type = (PacketType)SBufferHelper.ConvertBufferToDataLength(buffer, cursor); + cursor += TYPE_LENGTH; - this.DataLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, cursor)); + this.DataLength = SBufferHelper.ConvertBufferToDataLength(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); + byte[] type = SBufferHelper.ConvertPacketTypeToBuffer(this.Type); + byte[] dataLength = SBufferHelper.ConvertDataLengthToBuffer(this.DataLength); + + return SBufferHelper.GetBuffer(HEADER_LENGTH, type, dataLength); + } + + public static int GetDataSize(params byte[][] data) + { + int size = 0; + for (int i = 0; i < data.Length; i++) + { + size += data[i].Length; + } + + return size; } } } diff --git a/MySolution/STcpHelper/Packet/STcpTextPacket.cs b/MySolution/STcpHelper/Packet/STcpTextPacket.cs index 46c60c3..5c15d42 100644 --- a/MySolution/STcpHelper/Packet/STcpTextPacket.cs +++ b/MySolution/STcpHelper/Packet/STcpTextPacket.cs @@ -19,8 +19,8 @@ namespace STcpHelper.Packet public STcpTextPacket(byte[] dataBuffer) { int cursor = 0; - short length = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(dataBuffer, cursor)); - cursor += sizeof(short); + int length = SBufferHelper.ConvertBufferToDataLength(dataBuffer, cursor); + cursor += sizeof(int); this.Text = SEncoding.GetString(dataBuffer, cursor, length); } @@ -28,13 +28,14 @@ namespace STcpHelper.Packet public byte[] Serialize() { byte[] data = SEncoding.GetBytes(Text); - byte[] dataLength = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)data.Length)); + byte[] dataLength = SBufferHelper.ConvertDataLengthToBuffer(data.Length); - // 4bytes header - STcpPacketHeader header = new STcpPacketHeader(PacketType.TEXT, dataLength.Length + data.Length); + int dataSize = STcpPacketHeader.GetDataSize(data, dataLength); - // [header][2bytes text size][n bytes text] - return SBufferHelper.GetBuffer(4 + dataLength.Length + data.Length, header.Serialize(), dataLength, data); + STcpPacketHeader header = new STcpPacketHeader(PacketType.TEXT, dataSize); + + return SBufferHelper.GetBuffer( + STcpPacketHeader.HEADER_LENGTH + dataSize, header.Serialize(), dataLength, data); } } } diff --git a/MySolution/STcpHelper/STcpClient.cs b/MySolution/STcpHelper/STcpClient.cs index d52a221..f8606e3 100644 --- a/MySolution/STcpHelper/STcpClient.cs +++ b/MySolution/STcpHelper/STcpClient.cs @@ -19,8 +19,10 @@ namespace STcpHelper private TcpClient _client; private NetworkStream _stream; - private readonly int HEADER_SIZE = 4; - private readonly int BUFFER_SIZE = 1024; + private readonly int HEADER_SIZE = STcpPacketHeader.HEADER_LENGTH; + // private readonly int BUFFER_SIZE = 1024; + + private readonly string FILE_SAVE_FOLDER = @".\"; public async void Connect(string ip, int port) { @@ -34,7 +36,7 @@ namespace STcpHelper _ = Task.Run(async () => { byte[] headerBuffer = new byte[HEADER_SIZE]; - byte[] dataBuffer = new byte[BUFFER_SIZE]; + byte[] dataBuffer; while (true) { Thread.Sleep(50); @@ -42,18 +44,21 @@ namespace STcpHelper break; int headerBytesRead = await _stream.ReadAsync(headerBuffer, 0, HEADER_SIZE); - if (headerBytesRead != 4) + if (headerBytesRead != HEADER_SIZE) { WriteError(new Exception("Cannot read header")); return; } STcpPacketHeader header = new STcpPacketHeader(headerBuffer); - short dataSize = header.DataLength; + int dataSize = header.DataLength; + dataBuffer = new byte[dataSize]; + int totalRecv = 0; while (totalRecv < dataSize) { int dataBytesRead = await _stream.ReadAsync(dataBuffer, totalRecv, dataSize - totalRecv); + totalRecv += dataBytesRead; } @@ -70,6 +75,11 @@ namespace STcpHelper WriteMessage(client); } } + else if (header.Type == PacketType.RES_FILE) + { + STcpFileResPacket packet = new STcpFileResPacket(dataBuffer, FILE_SAVE_FOLDER); + WriteMessage($"File({packet.FileName}) saved."); + } } }, _cts.Token); } @@ -111,6 +121,19 @@ namespace STcpHelper } } + public async void RequireFile(string path) + { + try + { + STcpFileReqPacket packet = new STcpFileReqPacket(path); + await _stream.WriteAsync(packet.Serialize()); + } + catch (Exception ex) + { + WriteError(ex); + } + } + public void Close() { try diff --git a/MySolution/STcpHelper/STcpServer.cs b/MySolution/STcpHelper/STcpServer.cs index f0d13a6..3aae3fa 100644 --- a/MySolution/STcpHelper/STcpServer.cs +++ b/MySolution/STcpHelper/STcpServer.cs @@ -11,7 +11,7 @@ namespace STcpHelper private List _clients; - private readonly int HEADER_SIZE = 4; + private readonly int HEADER_SIZE = STcpPacketHeader.HEADER_LENGTH; private readonly int BUFFER_SIZE; private int _port; @@ -56,14 +56,14 @@ namespace STcpHelper while (true) { int headerBytesRead = await stream.ReadAsync(headerBuffer, 0, HEADER_SIZE); - if (headerBytesRead != 4) + if (headerBytesRead != HEADER_SIZE) { WriteError(new Exception("Cannot read header")); return; } STcpPacketHeader header = new STcpPacketHeader(headerBuffer); - short dataSize = header.DataLength; + int dataSize = header.DataLength; int totalRecv = 0; while (totalRecv < dataSize) { @@ -71,10 +71,11 @@ namespace STcpHelper totalRecv += dataBytesRead; } + WriteMessage($"[{client.Client.RemoteEndPoint.ToString()}] Type: {header.Type.ToString()}"); + if (header.Type == PacketType.TEXT) { STcpTextPacket packet = new STcpTextPacket(dataBuffer); - WriteMessage($"[{client.Client.RemoteEndPoint.ToString()}] Type: {header.Type.ToString()}"); // Broadcast BroadcastMessage(packet.Text, client); @@ -83,11 +84,18 @@ namespace STcpHelper else if (header.Type == PacketType.REQ_CLIENT_LIST) { STcpClientListResPacket packet = new STcpClientListResPacket(_clients); - WriteMessage($"[{client.Client.RemoteEndPoint.ToString()}] Type: {header.Type.ToString()}"); // Send SendPacket(packet, client); } + else if (header.Type == PacketType.REQ_FILE) + { + STcpFileReqPacket recvPacket = new STcpFileReqPacket(dataBuffer); + STcpFileResPacket packet = new STcpFileResPacket(recvPacket.Path); + + // Send async + SendAsyncPacket(packet, client); + } if (!IsClientConnected(client)) break; @@ -123,6 +131,26 @@ namespace STcpHelper if (!IsClientConnected(requester)) return; + if (responseByte.Length < BUFFER_SIZE) + requester.GetStream().WriteAsync(responseByte, 0, responseByte.Length); + else + { + int totalSend = 0; + while (totalSend < responseByte.Length) + { + int sendCount = responseByte.Length - totalSend < BUFFER_SIZE ? responseByte.Length - totalSend : BUFFER_SIZE; + requester.GetStream().WriteAsync(responseByte, totalSend, sendCount); + totalSend += sendCount; + } + } + } + + private async void SendAsyncPacket(ISTcpAsyncPacket packet, TcpClient requester) + { + byte[] responseByte = await packet.Serialize(); + if (!IsClientConnected(requester)) + return; + requester.GetStream().WriteAsync(responseByte, 0, responseByte.Length); } diff --git a/MySolution/SerialComApp/SerialCommApp.resx b/MySolution/SerialComApp/SerialCommApp.resx index b432cfb..bb944b5 100644 --- a/MySolution/SerialComApp/SerialCommApp.resx +++ b/MySolution/SerialComApp/SerialCommApp.resx @@ -121,7 +121,7 @@ iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL - DgAACw4BQL7hQQAAAsBJREFUaEPt2cnLTXEcx/FrzJCphJ0F2diIbEQokWFnzhClyFB6yEJEyh+gUMaU + DQAACw0B7QfALAAAAsBJREFUaEPt2cnLTXEcx/FrzJCphJ0F2diIbEQokWFnzhClyFB6yEJEyh+gUMaU WdlYWLBRiszjAmFjaUgZMvP+LE6dTp9z7jnnnt990PnUa/N07+/7u/ee3/g06tSpU+efzihswFncxzt8 x1e8xm0cx2oMx1+R7liOG/hdwC9cxXx0Q6dkNp7DdbCIh5iKtqUvjsF1piz9InvQE0EzDPfgOlGFKxiE IBmKZ3CF03zBt8TfmrmFAag0fXAXrmCcXrMd4zAYUYZgInbjCdx74y6h0sF9BK5QRANxJvKkKxaj2QSw diff --git a/MySolution/TAPClient/Program.cs b/MySolution/TAPClient/Program.cs index c1cf4be..9f5dbde 100644 --- a/MySolution/TAPClient/Program.cs +++ b/MySolution/TAPClient/Program.cs @@ -16,9 +16,16 @@ namespace TAPClient string input = Console.ReadLine(); switch (input.ToLower()) { + case "": + break; case "rcl": client.RequireClientList(); break; + case "df": + Console.Write("File path: "); + string path = Console.ReadLine(); + client.RequireFile(path); + break; default: client.SendMessage(input); break;