I am learning sockets and currently; I am struggling with broadcasting message to all connected clients.
Server is simply starting up with this code:
public static int Main(String[] args)
{
Thread t1 = new Thread(Test);
t1.Start();
#region Start listening to socket
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
Console.WriteLine("[{0}] Server started listening!", DateTime.Now);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
#endregion
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
return 0;
}
There, I start socket to listen to if someone sends message.
As you can see, I have thread up there and I want that thread to send all connected users some message from time to time (for now all time few bytes just for testing).
Here is that method from thread
private static void Test()
{
while (true)
{
for (int i = 0; i < Players.Length; i++)
{
if (Players[i] == null)
continue;
Socket cs = new Socket(Players[i].IPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
cs.Bind(Players[i].IPEndPoint);
byte[] data = Encoding.ASCII.GetBytes("Random data");
cs.Send(data);
}
}
}
This method is only last try but not successful. Problem is it drops me errors that are:
socket is reference of null.
In this case but in any case I couldn't manage to send message to each and every client.
Here is how I track client connection to server.
case "0": // Client tries to connect to server
if (nClients >= MAX_PLAYERS)
{
Send(handler, "Too many players. Try again later.");
return;
}
for (int i = 0; i < MAX_PLAYERS; i++)
{
if(Players[i] == null)
{
Players[i] = new Client();
Players[i].Name = parts[1].ToString();
Players[i].IPEndPoint = handler.RemoteEndPoint as IPEndPoint;
Send(handler, String.Format("1|{0}", i));
Console.WriteLine("[{0}] Succesfully registered client ID: {1}, NAME: {2}!", DateTime.Now, i, parts[1].ToString());
i = MAX_PLAYERS;
nClients++;
}
}
break;
This is only part of code focused on handling connect message which is located inside my method:
private static void HandleMessages(string message, Socket handler)
and I call it from here:
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
string message = content.Remove(content.Length - 5, 5);
HandleMessages(message, handler);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}