ClientSocket

main
syneffort 1 year ago
parent 797c061bbf
commit dbea3660a7
  1. 54
      PLibs/ConsoleApp1/ConsoleApp1.csproj
  2. 42
      PLibs/ConsoleApp1/Program.cs
  3. 36
      PLibs/ConsoleApp1/Properties/AssemblyInfo.cs
  4. 88
      PLibs/HeadTailSocketFW/ByteQueue.cs
  5. 243
      PLibs/HeadTailSocketFW/ClientSocket.cs
  6. 64
      PLibs/HeadTailSocketFW/HeadTailSocket.cs
  7. 46
      PLibs/HeadTailSocketFW/HeadTailSocketFW.csproj
  8. 36
      PLibs/HeadTailSocketFW/Properties/AssemblyInfo.cs
  9. 14
      PLibs/PLibs.sln

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{634E2E96-AFDD-4C4B-8C1B-E068889DA360}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ConsoleApp1</RootNamespace>
<AssemblyName>ConsoleApp1</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HeadTailSocketFW\HeadTailSocketFW.csproj">
<Project>{08d0b4d1-328f-4bfd-8af3-f8fe66b5981d}</Project>
<Name>HeadTailSocketFW</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,42 @@
using HeadTailSocketFW;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
string ip = "127.0.0.1";
int port = 5300;
HeadTailSocket socket = new HeadTailSocket();
socket.Head = new byte[] { 0x02 }; //STX
socket.Tail = new byte[] { 0x03 }; //ETX
socket.OnReceived -= Socket_OnReceived;
socket.OnReceived += Socket_OnReceived;
while (true)
{
if (socket == null)
continue;
if (!socket.IsConnected)
socket.Connect(ip, port);
Thread.Sleep(1000);
}
}
private static void Socket_OnReceived(object sender, byte[] buffer)
{
string rawPacket = Encoding.ASCII.GetString(buffer);
Console.WriteLine(rawPacket);
}
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("ConsoleApp1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApp1")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("634e2e96-afdd-4c4b-8c1b-e068889da360")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HeadTailSocketFW
{
public class ByteQueue
{
private object _lock = new object();
private Queue<byte> _queue;
public int Count { get { return _queue.Count; } }
public ByteQueue(int capacity)
{
lock (_lock)
{
_queue = new Queue<byte>(capacity);
}
}
public void Enqueue(byte item)
{
lock (_lock)
{
_queue.Enqueue(item);
}
}
public void Enqueue(byte[] array)
{
lock (_lock)
{
for (int i = 0; i < array.Length; i++)
{
_queue.Enqueue(array[i]);
}
}
}
public byte Dequeue()
{
lock (_lock)
{
return _queue.Dequeue();
}
}
public byte[] Dequeue(int size)
{
lock (_lock)
{
byte[] array = new byte[size];
for (int i = 0; i < array.Length; i++)
{
array[i] = _queue.Dequeue();
}
return array;
}
}
public int FindIndex(byte[] item, int startIndex = 0)
{
if (item == null || item.Length < 1)
return -1;
byte[] queueBytes = new byte[_queue.Count];
_queue.CopyTo(queueBytes, 0);
for (int i = startIndex; i < queueBytes.Length - item.Length + 1; i++)
{
if (queueBytes.Skip(i).Take(item.Length).SequenceEqual(item))
return i;
}
return -1;
}
public void Clear()
{
lock (_lock)
{
_queue.Clear();
}
}
}
}

@ -0,0 +1,243 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Timers;
namespace HeadTailSocketFW
{
public delegate void BufferReceivedHandler(object sender, byte[] buffer);
public delegate void ConnectionStatusHandler(object sender);
public class ClientSocket
{
protected readonly int MAX_BUFFER_SIZE = 8 * 1024;
protected readonly int SOCKET_BUFFER_SIZE = 2 * 1024; // 2KB
protected readonly int SEND_SOCKET_BUFFER_SIZE = 8 * 1024; // 8KB
protected Socket _socket;
protected byte[] _receiveSocketBuffer;
protected byte[] _sendSocketBuffer;
protected ByteQueue _buffer;
private ManualResetEvent _sendEvent = new ManualResetEvent(true);
private IPEndPoint _endPoint;
private bool _disposed;
public bool IsConnected => _socket != null && _socket.Connected;
public event BufferReceivedHandler OnReceived;
public event ConnectionStatusHandler OnConnected;
public event ConnectionStatusHandler OnDisconnected;
public bool EnableDebug { get; set; } = false;
public ClientSocket(int bufferSize = 2, int sendBufferSize = 8)
{
SOCKET_BUFFER_SIZE = bufferSize * 1024 > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : bufferSize * 1024;
SEND_SOCKET_BUFFER_SIZE = sendBufferSize * 1024 > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : sendBufferSize * 1024;
_receiveSocketBuffer = new byte[SOCKET_BUFFER_SIZE];
_sendSocketBuffer = new byte[SEND_SOCKET_BUFFER_SIZE];
_buffer = new ByteQueue(MAX_BUFFER_SIZE);
}
public bool Connect(string address, int port)
{
Disconnect();
try
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress endPointAddress = IPAddress.Parse(address.Trim());
_endPoint = new IPEndPoint(endPointAddress, port);
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.Connect] {ex.Message}");
return false;
}
return Reconnect();
}
public bool Connect(string address, int port, int timeout)
{
Disconnect();
try
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress endPointAddress = IPAddress.Parse(address.Trim());
_endPoint = new IPEndPoint(endPointAddress, port);
_socket.Connect(_endPoint);
_socket.Blocking = true;
}
catch (SocketException sockEx)
{
Debug.WriteLine($"[ClientSocket.Connect.Socket] {sockEx.Message}");
if (sockEx.SocketErrorCode != SocketError.WouldBlock)
{
_socket.Close();
return false;
}
if (!_socket.Poll(timeout * 1000, SelectMode.SelectWrite))
{
_socket.Close();
Debug.WriteLine($"[ClientSocket.Connect.Socket] Failed to connect.");
return false;
}
return true;
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.Connect] {ex.Message}");
return false;
}
return true;
}
public bool Reconnect()
{
if (_endPoint == null)
throw new Exception("EndPoint is not initialized.");
if (_socket.Connected)
_socket.Disconnect(true);
bool isSuccess = false;
try
{
_socket.Connect(_endPoint);
_socket.BeginReceive(_receiveSocketBuffer, 0, SOCKET_BUFFER_SIZE, SocketFlags.None, ReceiveCallback, this);
isSuccess = true;
}
catch (SocketException sockEx)
{
Debug.WriteLine($"[ClientSocket.Reconnect.Socket] {sockEx.ToString()}");
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.Reconnect] {ex.ToString()}");
throw;
}
if (isSuccess && OnConnected != null)
OnConnected(this);
return isSuccess;
}
public void Disconnect()
{
if (_socket == null)
return;
try
{
_socket.Close();
_socket = null;
if (OnDisconnected != null)
OnDisconnected(this);
}
catch (Exception)
{
throw;
}
}
protected void ReceiveCallback(IAsyncResult ar)
{
if (_socket == null)
return;
try
{
int receiveCount = _socket.EndReceive(ar);
if (receiveCount == 0)
{
Disconnect();
return;
}
try
{
_buffer.Enqueue(_receiveSocketBuffer);
if (EnableDebug)
{
if (EnableDebug)
Debug.WriteLine($"SocketDebug[{_endPoint.ToString()}] {Encoding.ASCII.GetString(_receiveSocketBuffer)}");
}
Interpret();
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.ReceiveCallback.Interpret] {ex.Message}");
_buffer.Clear();
}
if (_socket != null)
_socket.BeginReceive(_receiveSocketBuffer, 0, SOCKET_BUFFER_SIZE, SocketFlags.None, ReceiveCallback, this);
}
catch (SocketException sockEx)
{
Debug.WriteLine($"[ClientSocket.ReceiveCallback.Socket] {sockEx.Message}");
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.ReceiveCallback] {ex.Message}");
}
}
protected virtual void Interpret()
{
RaiseReceivedEvent(this, _buffer.Dequeue(_buffer.Count));
}
protected void RaiseReceivedEvent(object sender, byte[] buffer)
{
if (OnReceived != null)
OnReceived(sender, buffer);
}
public virtual void Send(byte[] data)
{
byte[] array = new byte[data.Length];
Array.Copy(data, array, data.Length);
try
{
_sendEvent.WaitOne();
_sendEvent.Reset();
_socket.BeginSend(array, 0, array.Length, SocketFlags.None, SendCallback, this);
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.Send] -Message: {Encoding.ASCII.GetString(array)} -Exception: {ex.Message}");
}
}
protected void SendCallback(IAsyncResult ar)
{
_sendEvent.Set();
try
{
int sendCount = _socket.EndSend(ar);
}
catch (Exception ex)
{
Debug.WriteLine($"[ClientSocket.SendCallback] {ex.Message}");
}
}
}
}

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace HeadTailSocketFW
{
public class HeadTailSocket : ClientSocket
{
public byte[] Head { get; set; }
public byte[] Tail { get; set; }
public bool IsIncludeHeadTail { get; set; }
protected override void Interpret()
{
// Both head and tail are not exist.
if ((Head == null || Head.Length < 1) && (Tail == null || Tail.Length < 1))
{
RaiseReceivedEvent(this, _buffer.Dequeue(_buffer.Count));
return;
}
byte[] head;
byte[] tail;
// Head only
if ((Head != null || Head.Length > 0) && (Tail == null || Tail.Length < 1))
{
head = Head;
tail = Head;
}
// Tail only
if ((Head != null || Head.Length > 0) && (Tail == null || Tail.Length < 1))
{
head = Tail;
tail = Tail;
}
// Both
{
head = Head;
tail = Tail;
}
int startIndex = _buffer.FindIndex(head);
if (startIndex < 0)
return;
int endIndex = _buffer.FindIndex(tail, startIndex + 1);
if (endIndex < 0)
return;
if (startIndex >= endIndex)
return;
byte[] rawPacket = _buffer.Dequeue(endIndex + 1);
byte[] packet = new byte[endIndex - startIndex - 1];
Array.Copy(rawPacket, startIndex + 1, packet, 0, packet.Length);
RaiseReceivedEvent(this, packet);
}
}
}

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{08D0B4D1-328F-4BFD-8AF3-F8FE66B5981D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HeadTailSocketFW</RootNamespace>
<AssemblyName>HeadTailSocketFW</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ByteQueue.cs" />
<Compile Include="HeadTailSocket.cs" />
<Compile Include="ClientSocket.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("HeadTailSocketFW")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HeadTailSocketFW")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("08d0b4d1-328f-4bfd-8af3-f8fe66b5981d")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -3,12 +3,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34511.84
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelHelperCore", "ExcelHelperCore\ExcelHelperCore.csproj", "{0DC75403-4084-462B-936B-FA86EA90811B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExcelHelperCore", "ExcelHelperCore\ExcelHelperCore.csproj", "{0DC75403-4084-462B-936B-FA86EA90811B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelHelperFW", "ExcelHelperFW\ExcelHelperFW.csproj", "{FFEDB9F8-4285-493B-A30E-900C53D0CB55}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfHelperFW", "PdfHelperFW\PdfHelperFW.csproj", "{4F62138C-7B92-4FF8-8CB3-F37980AE99F2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeadTailSocketFW", "HeadTailSocketFW\HeadTailSocketFW.csproj", "{08D0B4D1-328F-4BFD-8AF3-F8FE66B5981D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{634E2E96-AFDD-4C4B-8C1B-E068889DA360}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -27,6 +31,14 @@ Global
{4F62138C-7B92-4FF8-8CB3-F37980AE99F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F62138C-7B92-4FF8-8CB3-F37980AE99F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F62138C-7B92-4FF8-8CB3-F37980AE99F2}.Release|Any CPU.Build.0 = Release|Any CPU
{08D0B4D1-328F-4BFD-8AF3-F8FE66B5981D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08D0B4D1-328F-4BFD-8AF3-F8FE66B5981D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08D0B4D1-328F-4BFD-8AF3-F8FE66B5981D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08D0B4D1-328F-4BFD-8AF3-F8FE66B5981D}.Release|Any CPU.Build.0 = Release|Any CPU
{634E2E96-AFDD-4C4B-8C1B-E068889DA360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{634E2E96-AFDD-4C4B-8C1B-E068889DA360}.Debug|Any CPU.Build.0 = Debug|Any CPU
{634E2E96-AFDD-4C4B-8C1B-E068889DA360}.Release|Any CPU.ActiveCfg = Release|Any CPU
{634E2E96-AFDD-4C4B-8C1B-E068889DA360}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Loading…
Cancel
Save