I've been working on this for a while (much longer than anticipated) and still can't seem to get a client-server working with C#. I think the main issue is my poor understanding of sockets in C# (I could implement this in Java no problem).
Any help finding my error(s) or helping me understand how to implement it properly would be appreciated. A code sample of how you would implement any one of my functions below would be great :)
The goal is to have multiple clients connected to a single server. Each client can send data updates/changes to the server, which then relays those updates to all other clients. This should be simple, right?
The server tracks all currently connected clients in a list along with the TcpClient object acquired from the connection.
The following code snippets are mostly entry points for threads and are supposed to do the following:
Server Side:
> Accept new clients
> Receive data from client
> Send data to clients
Client Side:
> Send data to server
> Receive data from sever
private void acceptClientConnection()
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 3000);
tcpListener.Start();
while (true)
{
TcpClient client = tcpListener.AcceptTcpClient();
clients.AddLast(new ConnClient(client, clients.Count));
Console.WriteLine("SERVER: client connected to server");
}
}
No problems so far, but I'm pretty sure I have issues here: The following code is where the server handles in-coming data from the clients. (This is run in a thread; one thread per client). The changes received are saved in a queue and are processed by another thread.
I feel this code should block, and wait for a message from the client, but I don't think that is happening.
private void handleClientComm()
{
while (true)
{
if (conn.Connected)
{
Console.WriteLine("SERVER: still connected, reading stream");
byte[] data = ReadToEnd(conn.GetStream());
lock (dataChanges)
{
dataChanges.AddLast(new Pair<int, byte[]>(clientIndex, data));
Monitor.PulseAll(dataChanges);
}
}
else Console.WriteLine("SERVER: not connected");
}
}
conn == the saved TcpClient object.
ReadToEnd(Stream) is a function I copied from a response to someone else question on here. I can't guarantee its correctness...
The following is the code that actually sends the updates to the clients:
I believe its working as intended.
private void synchData()
{
while (true)
{
lock (dataChanges)
{
Console.WriteLine("SERVER: waiting for data to synch");
while (dataChanges.Count == 0)
Monitor.Wait(dataChanges);
LinkedList<ConnClient>.Enumerator itr = clients.GetEnumerator();
for (int i = 0; i < clients.Count; i++ )
{
itr.MoveNext();
if(i == dataChanges.First.Value.index)
continue;
itr.Current.sendDataUpdate(dataChanges.First.Value.data);
}
dataChanges.RemoveFirst();
Console.WriteLine("SERVER: data change synched");
}
}
}
and
public void sendDataUpdate(byte[] data)
{
if (conn.Connected)
{
conn.GetStream().Write(data, 0, data.Length);
conn.GetStream().Flush();
}
}
The client is a little simpler, one thread for sending changes, one thread for receiving updates. If there is an issue here, I believe it will be while receiving updates - for the same reasons I think the server receiving data is wrong.
server = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(hostIP), hostPort);
server.Connect(serverEndPoint);
private void sendUpdates()
{
while (true)
{
lock (dataChanges)
{
while (dataChanges.Count == 0)
Monitor.Wait(dataChanges);
if (server.Connected)
{
NetworkStream nStream = server.GetStream();
nStream.Write(dataChanges.First.Value, 0, dataChanges.First.Value.Length);
nStream.Flush();
dataChanges.RemoveFirst();
Console.WriteLine("CLIENT: data change sent to server");
}
else Console.WriteLine("CLIENT: no longer connected to server");
}
}
}
private void receiveUpdates()
{
while(true)
{
if (server.Connected)
{
Console.WriteLine("CLIENT: waiting for data from server");
byte[] data = ReadToEnd(server.GetStream());
AbstractDataChange dChange = aData.deserialize(data);
Console.WriteLine("CLIENT: recieved data update from the server");
lock (aData)
{
aData.updateData(dChange);
}
}
else Console.WriteLine("CLIENT: no longer connected to server");
}
}
.