'C# / Unity - TCP Server with multiple changing clients
I'm trying to setup a TCP Server connected to multiple clients. The clients can change (disconnect, connect again). I'm not very familiar with network programming. So far my code looks like this:
Server:
private void StartReceiveThread()
{
ReceiveThread = new Thread(() => ListenForMessages());
ReceiveThread.IsBackground = true;
ThreadRunning = true;
ReceiveThread.Start();
}
private void ListenForMessages()
{
try
{
TcpListener = new TcpListener(IPAddress.Parse(IP), Port);
TcpListener.Start();
Debug.Log("TCP Server is listening");
while (ThreadRunning)
{
TcpClient client = TcpListener.AcceptTcpClient();
int id = ConnectedClients.Count;
lock (ConnectedClients)
{
ConnectedClients.Add(id, client);
}
Thread t = new Thread(HandleClients);
t.Start(id);
}
}
catch (Exception exception)
{
Debug.Log(exception.Message);
}
}
private void HandleClients(object o)
{
int id = (int)o;
TcpClient client;
lock (ConnectedClients)
{
client = ConnectedClients[id];
}
while (ThreadRunning)
{
NetworkStream stream = client.GetStream();
byte[] fileSizeBytes = new byte[4];
int length = stream.Read(fileSizeBytes, 0, 4);
int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
int bufferSize = 1024;
int bytesRead = 0;
while (bytesLeft > 0)
{
int curDataSize = Math.Min(bufferSize, bytesLeft);
if (client.Available < curDataSize)
{
curDataSize = client.Available;
}
length = stream.Read(data, bytesRead, curDataSize);
bytesRead += curDataSize;
bytesLeft -= curDataSize;
}
if (data.Length > 0)
{
lock (IncomingQueue)
{
IncomingQueue.Enqueue(data);
}
}
}
lock (ConnectedClients)
{
ConnectedClients.Remove(id);
}
}
public void Send(byte[] packet)
{
if (!ThreadRunning)
{
return;
}
try
{
lock (ConnectedClients)
{
foreach (TcpClient client in ConnectedClients.Values)
{
NetworkStream stream = client.GetStream();
if (stream.CanWrite)
{
int bufferSize = 1024;
byte[] dataLength = BitConverter.GetBytes(packet.Length);
stream.Write(dataLength, 0, 4);
int bytesSent = 0;
int bytesLeft = packet.Length;
while (bytesLeft > 0)
{
int curDataSize = Math.Min(bufferSize, bytesLeft);
stream.Write(packet, bytesSent, curDataSize);
bytesSent += curDataSize;
bytesLeft -= curDataSize;
}
}
}
}
}
catch (Exception e)
{
Debug.Log(e.Message});
}
}
Client:
private void ConnectToServer()
{
ReceiveThread = new Thread(new ThreadStart(StartListening));
ReceiveThread.IsBackground = true;
ThreadRunning = true;
ReceiveThread.Start();
}
private void StartListening()
{
ListenForData();
}
private async Task ListenForData()
{
while (ThreadRunning)
{
TcpClient = new TcpClient();
if (!TcpClient.Connected)
{
try {
await TcpClient.ConnectAsync(IPAddress.Parse(IP), Port);
ClientConnected = true;
}
catch(Exception e)
{
Debug.Log($"Connection failed. Retry in one second.");
await Task.Delay(1000);
}
}
if (TcpClient.Connected)
{
Debug.Log("connected");
using (NetworkStream stream = TcpClient.GetStream())
{
byte[] fileSizeBytes = new byte[4];
int length = stream.Read(fileSizeBytes, 0, 4);
int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
int bufferSize = 1024;
int bytesRead = 0;
while (bytesLeft > 0)
{
int curDataSize = Math.Min(bufferSize, bytesLeft);
if (TcpClient.Available < curDataSize)
{
curDataSize = TcpClient.Available;
}
length = stream.Read(data, bytesRead, curDataSize);
bytesRead += curDataSize;
bytesLeft -= curDataSize;
}
if (data.Length > 0)
{
lock (IncomingQueue)
{
IncomingQueue.Enqueue(data);
}
}
}
}
}
TcpClient.Client.Shutdown(SocketShutdown.Send);
TcpClient.Close();
}
It works with one connected client. But as soon as I disconnect the client and start it again I get the following Message: "Unable to write data to the transport connection: An existing connection was aborted by the host computer."
I searched already a lot and couldn't find a better way so far. Any help would be much appreciated.
Thanks!
[EDIT] The accepted answer in this post was my inspiration for handling multiple clients: C# TCP/IP simple chat
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
