Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 25 additions & 35 deletions SimpleTCP/Message.cs
Original file line number Diff line number Diff line change
@@ -1,72 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SimpleTCP
{
public class Message
{
private TcpClient _tcpClient;
private System.Text.Encoding _encoder = null;
private byte _writeLineDelimiter;
private bool _autoTrim = false;
internal Message(byte[] data, TcpClient tcpClient, System.Text.Encoding stringEncoder, byte lineDelimiter)
private readonly Encoding _encoder;
private readonly byte _writeLineDelimiter;
private readonly bool _autoTrim;

public byte[] Data { get; }
public TcpClient TcpClient { get; }
public string MessageString => _autoTrim ? _encoder.GetString(Data).Trim() : _encoder.GetString(Data);


internal Message(byte[] data, TcpClient tcpClient, Encoding stringEncoder, byte lineDelimiter)
{
Data = data;
_tcpClient = tcpClient;
TcpClient = tcpClient;
_encoder = stringEncoder;
_writeLineDelimiter = lineDelimiter;
}

internal Message(byte[] data, TcpClient tcpClient, System.Text.Encoding stringEncoder, byte lineDelimiter, bool autoTrim)
internal Message(byte[] data, TcpClient tcpClient, Encoding stringEncoder, byte lineDelimiter, bool autoTrim)
{
Data = data;
_tcpClient = tcpClient;
TcpClient = tcpClient;
_encoder = stringEncoder;
_writeLineDelimiter = lineDelimiter;
_autoTrim = autoTrim;
}

public byte[] Data { get; private set; }
public string MessageString
{
get
{
if (_autoTrim)
{
return _encoder.GetString(Data).Trim();
}

return _encoder.GetString(Data);
}
}

public void Reply(byte[] data)
{
_tcpClient.GetStream().Write(data, 0, data.Length);
TcpClient.GetStream().Write(data, 0, data.Length);
}

public void Reply(string data)
{
if (string.IsNullOrEmpty(data)) { return; }
if (string.IsNullOrEmpty(data))
return;

Reply(_encoder.GetBytes(data));
}

public void ReplyLine(string data)
{
if (string.IsNullOrEmpty(data)) { return; }
if (string.IsNullOrEmpty(data))
return;

if (data.LastOrDefault() != _writeLineDelimiter)
{
Reply(data + _encoder.GetString(new byte[] { _writeLineDelimiter }));
} else
{
Reply(data);
Reply(data + _encoder.GetString(new[] { _writeLineDelimiter }));
return;
}
}

public TcpClient TcpClient { get { return _tcpClient; } }
Reply(data);
}
}
}
11 changes: 3 additions & 8 deletions SimpleTCP/Server/ConnectedClient.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SimpleTCP
namespace SimpleTCP.Server
{
public class ConnectedClient
{
public IPAddress ServerIP { get; internal set; }
public IPAddress ServerIp { get; internal set; }
public TcpClient Client { get; internal set; }
}
}
130 changes: 57 additions & 73 deletions SimpleTCP/Server/ServerListener.cs
Original file line number Diff line number Diff line change
@@ -1,93 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SimpleTCP.Server
{
internal class ServerListener
{
private TcpListenerEx _listener = null;
private List<TcpClient> _connectedClients = new List<TcpClient>();
private List<TcpClient> _disconnectedClients = new List<TcpClient>();
private SimpleTcpServer _parent = null;
private List<byte> _queuedMsg = new List<byte>();
private readonly List<TcpClient> _connectedClients = new List<TcpClient>();
private readonly List<TcpClient> _disconnectedClients = new List<TcpClient>();
private readonly SimpleTcpServer _parent;
private readonly List<byte> _queuedMsg = new List<byte>();
private byte _delimiter = 0x13;
private Thread _rxThread = null;
private Thread _rxThread;

public int ConnectedClientsCount
{
get { return _connectedClients.Count; }
}
public int ConnectedClientsCount => _connectedClients.Count;
public IEnumerable<TcpClient> ConnectedClients => _connectedClients;

public IEnumerable<TcpClient> ConnectedClients { get { return _connectedClients; } }
internal bool QueueStop { get; set; }
internal IPAddress IpAddress { get; }
internal int Port { get; }
internal int ReadLoopIntervalMs { get; set; }
internal TcpListenerEx Listener { get; }

internal ServerListener(SimpleTcpServer parentServer, IPAddress ipAddress, int port)
{
QueueStop = false;
_parent = parentServer;
IPAddress = ipAddress;
IpAddress = ipAddress;
Port = port;
ReadLoopIntervalMs = 10;

_listener = new TcpListenerEx(ipAddress, port);
_listener.Start();
Listener = new TcpListenerEx(ipAddress, port);
Listener.Start();

System.Threading.ThreadPool.QueueUserWorkItem(ListenerLoop);
ThreadPool.QueueUserWorkItem(ListenerLoop);
}

private void StartThread()
{
if (_rxThread != null) { return; }
_rxThread = new Thread(ListenerLoop);
_rxThread.IsBackground = true;
_rxThread.Start();
}

internal bool QueueStop { get; set; }
internal IPAddress IPAddress { get; private set; }
internal int Port { get; private set; }
internal int ReadLoopIntervalMs { get; set; }

internal TcpListenerEx Listener { get { return _listener; } }



private void ListenerLoop(object state)
private void ListenerLoop(object state)
{
while (!QueueStop)
{
try
{
RunLoopStep();
}
catch
catch
{

}

System.Threading.Thread.Sleep(ReadLoopIntervalMs);
Thread.Sleep(ReadLoopIntervalMs);
}
_listener.Stop();
Listener.Stop();
}

private static bool IsSocketConnected(Socket s)
{
// https://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c
var part1 = s.Poll(1000, SelectMode.SelectRead);
var part2 = (s.Available == 0);
return (!part1 || !part2) && s.Connected;
}


bool IsSocketConnected(Socket s)
{
// https://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if ((part1 && part2) || !s.Connected)
return false;
else
return true;
}


private void RunLoopStep()
{
if (_disconnectedClients.Count > 0)
Expand All @@ -102,54 +77,63 @@ private void RunLoopStep()
}
}

if (_listener.Pending())
if (Listener.Pending())
{
var newClient = _listener.AcceptTcpClient();
_connectedClients.Add(newClient);
var newClient = Listener.AcceptTcpClient();
_connectedClients.Add(newClient);
_parent.NotifyClientConnected(this, newClient);
}

_delimiter = _parent.Delimiter;

foreach (var c in _connectedClients)
foreach (var client in _connectedClients)
{
if ( IsSocketConnected(c.Client) == false)

if (IsSocketConnected(client.Client) == false)
{
_disconnectedClients.Add(c);
_disconnectedClients.Add(client);
}
int bytesAvailable = c.Available;

var bytesAvailable = client.Available;
if (bytesAvailable == 0)
{
//Thread.Sleep(10);
continue;
}

List<byte> bytesReceived = new List<byte>();
var bytesReceived = new List<byte>();

while (c.Available > 0 && c.Connected)
while (client.Available > 0 && client.Connected)
{
byte[] nextByte = new byte[1];
c.Client.Receive(nextByte, 0, 1, SocketFlags.None);
var nextByte = new byte[1];
client.Client.Receive(nextByte, 0, 1, SocketFlags.None);
bytesReceived.AddRange(nextByte);

if (nextByte[0] == _delimiter)
{
byte[] msg = _queuedMsg.ToArray();
var msg = _queuedMsg.ToArray();
_queuedMsg.Clear();
_parent.NotifyDelimiterMessageRx(this, c, msg);
} else
_parent.NotifyDelimiterMessageRx(this, client, msg);
}
else
{
_queuedMsg.AddRange(nextByte);
}
}

if (bytesReceived.Count > 0)
{
_parent.NotifyEndTransmissionRx(this, c, bytesReceived.ToArray());
}
_parent.NotifyEndTransmissionRx(this, client, bytesReceived.ToArray());
}
}
}

//Think this method should be deleted
private void StartThread()
{
if (_rxThread != null) { return; }
_rxThread = new Thread(ListenerLoop) { IsBackground = true };
_rxThread.Start();
}
}
}
27 changes: 11 additions & 16 deletions SimpleTCP/Server/TcpListenerEx.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SimpleTCP.Server
{
/// <inheritdoc />
/// <summary>
/// Wrapper around TcpListener that exposes the Active property
/// See: http://stackoverflow.com/questions/7630094/is-there-a-property-method-for-determining-if-a-tcplistener-is-currently-listeni
/// </summary>
public class TcpListenerEx : TcpListener
{
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Net.Sockets.TcpListener"/> class with the specified local endpoint.
/// Initializes a new instance of the <see cref="T:System.Net.Sockets.TcpListener" /> class with the specified local endpoint.
/// </summary>
/// <param name="localEP">An <see cref="T:System.Net.IPEndPoint"/> that represents the local endpoint to which to bind the listener <see cref="T:System.Net.Sockets.Socket"/>. </param><exception cref="T:System.ArgumentNullException"><paramref name="localEP"/> is null. </exception>
public TcpListenerEx(IPEndPoint localEP) : base(localEP)
/// <param name="localEp">An <see cref="T:System.Net.IPEndPoint" /> that represents the local endpoint to which to bind the listener <see cref="T:System.Net.Sockets.Socket" />. </param><exception cref="T:System.ArgumentNullException"><paramref name="localEp" /> is null. </exception>
public TcpListenerEx(IPEndPoint localEp) : base(localEp)
{
}

/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Net.Sockets.TcpListener"/> class that listens for incoming connection attempts on the specified local IP address and port number.
/// Initializes a new instance of the <see cref="T:System.Net.Sockets.TcpListener" /> class that listens for incoming connection attempts on the specified local IP address and port number.
/// </summary>
/// <param name="localaddr">An <see cref="T:System.Net.IPAddress"/> that represents the local IP address. </param><param name="port">The port on which to listen for incoming connection attempts. </param><exception cref="T:System.ArgumentNullException"><paramref name="localaddr"/> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="port"/> is not between <see cref="F:System.Net.IPEndPoint.MinPort"/> and <see cref="F:System.Net.IPEndPoint.MaxPort"/>. </exception>
public TcpListenerEx(IPAddress localaddr, int port) : base(localaddr, port)
/// <param name="localAddr">An <see cref="T:System.Net.IPAddress" /> that represents the local IP address. </param><param name="port">The port on which to listen for incoming connection attempts. </param><exception cref="T:System.ArgumentNullException"><paramref name="localAddr" /> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="port" /> is not between <see cref="F:System.Net.IPEndPoint.MinPort" /> and <see cref="F:System.Net.IPEndPoint.MaxPort" />. </exception>
public TcpListenerEx(IPAddress localAddr, int port) : base(localAddr, port)
{
}

public new bool Active
{
get { return base.Active; }
}
public new bool Active => base.Active;
}
}
Loading