Send a message back to the client list at any given time using asynchronous sockets in C #

I have an asynchronous server installed, it works fine, connecting, receiving and sending a message to the communication client.

The server itself is a Game-World-Server (mmorpg style). When a user sends his location to where he is, I need to click this for all clients using PlayerPositionNotice. I know that the basic material is missing here, but when I try to save the StateObject that was created in the accept method and use this socket to send information to the player at any given time, it fails because the socket is closed. = / I donโ€™t know why this is happening, and I would look for a couple of engines, but returned empty.

This is how I created my server:

First we have global stuff:

public StateManager _stateManager = new StateManager(); public bool IsClosing = false; private const int _port = 1025; private IPHostEntry _localhost; private IPEndPoint _endpoint; private Socket _serverSocket; private Thread _serverThread; 

Secondly, we initialize the material:

  public void Start() { _serverThread = new Thread(Initialize); _serverThread.Start(); } /// <summary> /// Main entry point for the server /// </summary> private void Initialize() { Console.WriteLine("Server Main Socket Thread Initialized."); _localhost = Dns.GetHostEntry(Dns.GetHostName()); try { _endpoint = new IPEndPoint(_localhost.AddressList[0], _port); _serverSocket = new Socket(_endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _serverSocket.Bind(_endpoint); _serverSocket.Listen(100); _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket); } catch (ArgumentOutOfRangeException) { Console.WriteLine(" >> Port number " + _port + " would seem to be invalid, should be between 1024 and 65000"); } catch (SocketException) { Console.WriteLine(" >> Could not create socket, check to make sure not duplicating port"); } catch (Exception e) { Console.WriteLine(" >> Error occured while binding socket, IE:" + e.InnerException); } } 

So far so good, I expect .. And now for the rest of the server class.

  private void acceptCallback(IAsyncResult result) { Console.WriteLine("Connection Accepted"); StateObject state = null; try { state = new StateObject { workSocket = ((Socket)result.AsyncState).EndAccept(result) }; _stateManager.AddConnection(state); state.workSocket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), state); _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket); } catch (SocketException) { _stateManager.RemoveConnection(state); _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket); } catch (Exception) { _stateManager.RemoveConnection(state); _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket); } } private void receiveCallback(IAsyncResult result) { var state = (StateObject)result.AsyncState; try { // Buffer and count bytes read int bytesRead = state.workSocket.EndReceive(result); if (!state.workSocket.Connected) _stateManager.RemoveConnection(state); if (bytesRead > 0) { // Parse the message to the protocol manager and return a reply var replyingData = ProtocolManager.Parse(state.buffer); if (replyingData != null) Send(replyingData, state); //Queue the next receive state.workSocket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), state); } else { _stateManager.RemoveConnection(state); } } catch (SocketException e) { _stateManager.RemoveConnection(state); } } public bool Send(byte[] message, StateObject state) { Console.WriteLine("Sending " + message.Length + " bytes"); if (state != null && state.workSocket.Connected) { lock (state.workSocket) { //we use a blocking mode send, no async on the outgoing //since this is primarily a multithreaded application, shouldn't cause problems to send in blocking mode state.workSocket.Send(message, message.Length, SocketFlags.None); } } else return false; return true; } 

StateManager contains a list of StateObjects. Below you can see how I create them.

STATE MANAGER:

 public class StateManager { private List<StateObject> _connections = new List<StateObject>(); public void AddConnection(StateObject so) { lock (_connections) { _connections.Add(so); } } public void RemoveConnection(StateObject so) { if (so.workSocket != null) { so.workSocket.Close(); lock (_connections) { _connections.Remove(so); } } } } 

STATE OBJECT

 public class StateObject { public Socket workSocket = null; public const int BufferSize = 1024; public byte[] buffer = new byte[BufferSize]; public StringBuilder sb = new StringBuilder(); } 

My problem is that whenever someone from this list sends something, I want to send a notification about all other clients. How and where can I implement this? Can anyone hit me in the right direction? =)

+4
source share
1 answer

This code seems to be correct, and I donโ€™t know why you get the "socket is closed" error, but there is another problem: there is a Send (byte [] message, StateObject state) method, because you call it upon receipt from the user and send Received data back to this user (not to all other users to notice them)

As you said, if you need to send a new location to all other users:

Call this method instead of the Send message (byte [], StateObject) when you receive the new location.

 public void NoticeAllusers(byte []buffer,StateObject state) { foreach(StateObject obj in _stateManager._connections) { if (obj != state) { obj.workSocket.BeginSend(buffer,<parameters you>...., new AsyncCallback(OnSend) state.workSocket); } } } public void OnSend(IAsyncResult ar) { try { Socket sock = (Socket)ar.AsyncState; sock.EndSend(ar); } catch { } } 

Hope this helps a bit :)

+2
source

Source: https://habr.com/ru/post/1397587/


All Articles