Skip to content

Commit 1a115ad

Browse files
support multiple connections in tcp server
1 parent d903a00 commit 1a115ad

File tree

7 files changed

+358
-284
lines changed

7 files changed

+358
-284
lines changed

TcpUdpTool/App.config

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
<?xml version="1.0" encoding="utf-8" ?>
2-
<configuration>
3-
<configSections>
4-
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
5-
<section name="TcpUdpTool.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
6-
</sectionGroup>
7-
</configSections>
8-
<startup>
9-
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
10-
</startup>
11-
<userSettings>
12-
<TcpUdpTool.Properties.Settings>
13-
<setting name="Encoding" serializeAs="String">
14-
<value>65001</value>
15-
</setting>
16-
<setting name="IPv6Support" serializeAs="String">
17-
<value>False</value>
18-
</setting>
19-
<setting name="HistoryEntries" serializeAs="String">
20-
<value>100</value>
21-
</setting>
22-
<setting name="HistoryInfoTimestamp" serializeAs="String">
23-
<value>True</value>
24-
</setting>
25-
<setting name="HistoryInfoIpAdress" serializeAs="String">
26-
<value>True</value>
27-
</setting>
28-
<setting name="ScrollToEnd" serializeAs="String">
29-
<value>True</value>
30-
</setting>
31-
</TcpUdpTool.Properties.Settings>
32-
</userSettings>
33-
</configuration>
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<configSections>
4+
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
5+
<section name="TcpUdpTool.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
6+
</sectionGroup>
7+
</configSections>
8+
<startup>
9+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
10+
</startup>
11+
<userSettings>
12+
<TcpUdpTool.Properties.Settings>
13+
<setting name="Encoding" serializeAs="String">
14+
<value>65001</value>
15+
</setting>
16+
<setting name="IPv6Support" serializeAs="String">
17+
<value>False</value>
18+
</setting>
19+
<setting name="HistoryEntries" serializeAs="String">
20+
<value>100</value>
21+
</setting>
22+
<setting name="HistoryInfoTimestamp" serializeAs="String">
23+
<value>True</value>
24+
</setting>
25+
<setting name="HistoryInfoIpAdress" serializeAs="String">
26+
<value>True</value>
27+
</setting>
28+
<setting name="ScrollToEnd" serializeAs="String">
29+
<value>True</value>
30+
</setting>
31+
</TcpUdpTool.Properties.Settings>
32+
</userSettings>
33+
</configuration>

TcpUdpTool/Model/TcpServer.cs

Lines changed: 133 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using System.Net;
35
using System.Net.Sockets;
4-
using System.Threading.Tasks;
6+
using System.Threading.Tasks;
57
using TcpUdpTool.Model.Data;
68
using TcpUdpTool.Model.EventArg;
79

@@ -13,23 +15,37 @@ public class TcpServer : IDisposable
1315
public event EventHandler<ReceivedEventArgs> Received;
1416
public event EventHandler<TcpServerStatusEventArgs> StatusChanged;
1517

16-
1718
private TcpListener _tcpServer;
18-
private System.Net.Sockets.TcpClient _connectedClient;
19+
private List<System.Net.Sockets.TcpClient> _connectedClients;
1920
private byte[] _buffer;
2021

2122

23+
public int NumConnectedClients
24+
{
25+
get
26+
{
27+
int count = 0;
28+
lock(_connectedClients)
29+
{
30+
count = _connectedClients.Count;
31+
}
32+
33+
return count;
34+
}
35+
}
36+
37+
2238
public TcpServer()
2339
{
40+
_connectedClients = new List<System.Net.Sockets.TcpClient>();
2441
_buffer = new byte[8192];
2542
}
2643

27-
2844
public void Start(IPAddress ip, int port)
2945
{
3046
if(_tcpServer != null)
3147
return;
32-
48+
3349
try
3450
{
3551
_tcpServer = new TcpListener(new IPEndPoint(ip, port));
@@ -56,30 +72,56 @@ public void Stop()
5672
}
5773
}
5874

59-
public async Task<TransmissionResult> SendAsync(Transmission msg)
60-
{
61-
if(_connectedClient == null)
62-
{
63-
return null;
64-
}
75+
public async Task<List<TransmissionResult>> SendAsync(Transmission msg)
76+
{
77+
var result = new List<TransmissionResult>();
6578

66-
IPEndPoint from = _connectedClient.Client.LocalEndPoint as IPEndPoint;
67-
IPEndPoint to = _connectedClient.Client.RemoteEndPoint as IPEndPoint;
79+
List<System.Net.Sockets.TcpClient> copy;
80+
lock (_connectedClients)
81+
{
82+
copy = _connectedClients.ToList();
83+
}
6884

69-
await _connectedClient.GetStream().WriteAsync(msg.Data, 0, msg.Length);
85+
foreach (var c in copy)
86+
{
87+
IPEndPoint from = c.Client.LocalEndPoint as IPEndPoint;
88+
IPEndPoint to = c.Client.RemoteEndPoint as IPEndPoint;
89+
90+
try
91+
{
92+
await c.GetStream().WriteAsync(msg.Data, 0, msg.Length);
93+
result.Add(new TransmissionResult { From = from, To = to });
94+
}
95+
catch(Exception)
96+
{
97+
DisconnectClient(c);
98+
}
99+
}
70100

71-
return new TransmissionResult() { From = from, To = to };
101+
return result;
72102
}
73103

74104
public void Disconnect()
75105
{
76106
// close client connection.
77-
if(_connectedClient != null)
78-
{
79-
_connectedClient.Close();
80-
_connectedClient = null;
81-
OnStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientDisconnected);
82-
}
107+
108+
List<System.Net.Sockets.TcpClient> copy;
109+
lock(_connectedClients)
110+
{
111+
copy = _connectedClients.ToList();
112+
}
113+
114+
foreach(var c in copy)
115+
{
116+
OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientDisconnected, c);
117+
c.Close();
118+
c.Dispose();
119+
}
120+
121+
lock(_connectedClients)
122+
{
123+
_connectedClients.Clear();
124+
}
83125
}
84126

85127

@@ -91,19 +133,13 @@ private void StartAcceptClient()
91133
{
92134
try
93135
{
94-
System.Net.Sockets.TcpClient client = await _tcpServer.AcceptTcpClientAsync();
95-
96-
if (_connectedClient == null)
97-
{
98-
_connectedClient = client;
99-
OnStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientConnected);
100-
StartReceive();
101-
}
102-
else
103-
{
104-
// only one connection allowed, close this request.
105-
client.Close();
106-
}
136+
var client = await _tcpServer.AcceptTcpClientAsync();
137+
lock(_connectedClients)
138+
{
139+
_connectedClients.Add(client);
140+
}
141+
OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientConnected, client);
142+
StartReceive(client);
107143
}
108144
catch(Exception ex)
109145
when(ex is SocketException || ex is ObjectDisposedException)
@@ -115,58 +151,84 @@ private void StartAcceptClient()
115151
});
116152
}
117153

118-
private void StartReceive()
154+
private void StartReceive(System.Net.Sockets.TcpClient client)
119155
{
120156
Task.Run(async () =>
121-
{
122-
while (_connectedClient != null)
123-
{
124-
try
125-
{
126-
int read = await _connectedClient.GetStream().ReadAsync(_buffer, 0, _buffer.Length);
127-
128-
if (read > 0)
129-
{
130-
byte[] data = new byte[read];
131-
Array.Copy(_buffer, data, read);
132-
133-
134-
Transmission msg = new Transmission(data, Transmission.EType.Received);
135-
msg.Destination = _connectedClient.Client.LocalEndPoint as IPEndPoint;
136-
msg.Origin = _connectedClient.Client.RemoteEndPoint as IPEndPoint;
137-
138-
Received?.Invoke(this, new ReceivedEventArgs(msg));
139-
}
140-
else
141-
{
142-
// server closed connection.
143-
Disconnect();
144-
break;
145-
}
146-
}
147-
catch (Exception e)
148-
when (e is ObjectDisposedException || e is InvalidOperationException)
149-
{
150-
Disconnect();
151-
break;
152-
}
157+
{
158+
bool stop = false;
159+
while (!stop)
160+
{
161+
try
162+
{
163+
int read = await client.GetStream().ReadAsync(_buffer, 0, _buffer.Length);
164+
165+
if (read > 0)
166+
{
167+
byte[] data = new byte[read];
168+
Array.Copy(_buffer, data, read);
169+
170+
Transmission msg = new Transmission(data, Transmission.EType.Received);
171+
msg.Destination = client.Client.LocalEndPoint as IPEndPoint;
172+
msg.Origin = client.Client.RemoteEndPoint as IPEndPoint;
173+
174+
Received?.Invoke(this, new ReceivedEventArgs(msg));
175+
}
176+
else
177+
{
178+
// server closed connection.
179+
DisconnectClient(client);
180+
stop = true;
181+
}
182+
}
183+
catch (Exception e)
184+
when (e is ObjectDisposedException || e is InvalidOperationException)
185+
{
186+
DisconnectClient(client);
187+
stop = true;
188+
}
153189
}
154190
});
155191
}
156192

157193
private void OnStatusChanged(TcpServerStatusEventArgs.EServerStatus status)
158194
{
159195
StatusChanged?.Invoke(this, new TcpServerStatusEventArgs(status,
160-
_tcpServer?.LocalEndpoint as IPEndPoint,
161-
_connectedClient?.Client.RemoteEndPoint as IPEndPoint));
196+
_tcpServer?.LocalEndpoint as IPEndPoint, null));
197+
}
198+
199+
private void OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus status, System.Net.Sockets.TcpClient client)
200+
{
201+
StatusChanged?.Invoke(this, new TcpServerStatusEventArgs(status,
202+
_tcpServer?.LocalEndpoint as IPEndPoint, client.Client.RemoteEndPoint as IPEndPoint));
203+
}
204+
205+
private void DisconnectClient(System.Net.Sockets.TcpClient client)
206+
{
207+
lock(_connectedClients)
208+
{
209+
_connectedClients.Remove(client);
210+
}
211+
212+
OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientDisconnected, client);
213+
client.Close();
214+
client.Dispose();
162215
}
163216

164217
public void Dispose()
165218
{
219+
lock (_connectedClients)
220+
{
221+
foreach (var c in _connectedClients)
222+
{
223+
c.Close();
224+
c.Dispose();
225+
}
226+
227+
_connectedClients.Clear();
228+
}
229+
166230
_tcpServer?.Stop();
167231
_tcpServer = null;
168-
_connectedClient?.Close();
169-
_connectedClient = null;
170232
}
171233
}
172234

TcpUdpTool/Properties/AssemblyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
[assembly: AssemblyConfiguration("")]
1313
[assembly: AssemblyCompany("Daniel Nilsson")]
1414
[assembly: AssemblyProduct("TcpUdpTool")]
15-
[assembly: AssemblyCopyright("Copyright © 2021 Daniel Nilsson")]
15+
[assembly: AssemblyCopyright("Copyright © 2022 Daniel Nilsson")]
1616
[assembly: AssemblyTrademark("")]
1717
[assembly: AssemblyCulture("")]
1818

@@ -51,7 +51,7 @@
5151
// You can specify all the values or you can default the Build and Revision Numbers
5252
// by using the '*' as shown below:
5353
// [assembly: AssemblyVersion("1.0.*")]
54-
[assembly: AssemblyVersion("1.0.0.0")]
55-
[assembly: AssemblyFileVersion("1.0.0.0")]
54+
[assembly: AssemblyVersion("1.1.0.0")]
55+
[assembly: AssemblyFileVersion("1.1.0.0")]
5656
[assembly: NeutralResourcesLanguage("en")]
5757

0 commit comments

Comments
 (0)