EDN Admin
Well-known member
Greetings,
Sorry for the long Title, but I wasnt to sure how to properly sum up the issue that I am currently facing.
At the moment I have a working Telnet server. It listens for incoming connections and for each new connection, it passes the Socket off to a Connection Manager class that manages all of the servers current connections. The Connection Manager
class instances a new Character class and provides it with a reference to the Socket so that it may communicate with the server. Im using a StreamReader and StreamWriter attached to the NetworkStream to send and receive user input. This doesnt
seem to be working properly with how I have it implemented.
When a user types the phrase "Say hello" I am removing "Say " and then looping through all of the current connections in the Connection Manager (which is static) and sending the content of the messages to each connected client. However on all of my
connected telnet clients, the message never gets sent or received. Im not sure if this is a multi-thread issue or if Im not using the streams correctly.
Any help would be greatly appreciated! I believe Ive included all of the code youd need to compile the code. The server is started with a new Instance of the Server class and then invoking the Server.Start() method.
Server Class
<pre class="prettyprint using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MudEngine.Core;
using MudEngine.Core.Interfaces;
using MudEngine.Game;
using MudEngine.Game.Characters;
namespace MudEngine.Networking
{
[Category("Networking")]
public class Server
{
[Category("Networking")]
[Description("The name of this server")]
public String Name { get; set; }
[Category("Networking")]
public Int32 Port { get; set; }
[Category("Networking")]
[Description("The Message Of The Day that is presented to users when they connect.")]
public String MOTD { get; set; }
[Category("Networking")]
[Description("Maximum number of people that can connect and play on this server at any time.")]
public Int32 MaxConnections { get; set; }
[Category("Networking")]
[Description("Maximum number of poeple that can be queued for connection.")]
public Int32 QueuedConnectionLimit { get; set; }
[Browsable(false)]
public Boolean Enabled { get; private set; }
/// <summary>
/// Sets up a server on the specified port.
/// </summary>
/// <param name="port </param>
/// <param name="maxConnections </param>
public Server(Int32 port)
{
Logger.WriteLine("Initializing Mud Server Settings");
this.Port = port;
this.MaxConnections = 50;
this.QueuedConnectionLimit = 20;
this.Name = "New Server";
this._Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._Server.Bind(new IPEndPoint(IPAddress.Any, this.Port));
}
/// <summary>
/// Starts the game server. It will listen on a different thread of incoming connections
/// </summary>
public void Start(StandardGame game)
{
//Start the server.
Logger.WriteLine("Starting Mud Server.");
//Start listening for connections
this._Server.Listen(this.QueuedConnectionLimit);
//Launch the new connections listener on a new thread.
this._ConnectionPool = new Thread(AcceptConnection);
this._ConnectionPool.Start();
//Flag the server as enabled.
this.Enabled = true;
//Save a reference to the currently active game
this._Game = game;
Logger.WriteLine("Server started.");
}
public void Stop()
{
//Flag the server as disabled.
this.Enabled = false;
//Stop the thread from listening for accepting new conections
this._ConnectionPool.Abort();
//Disconnect all of the currently connected clients.
ConnectionManager.DisconnectAll();
//Stop the server.
this._Server.Close();
}
private void AcceptConnection()
{
//While the server is enabled, constantly check for new connections.
while (this.Enabled)
{
//Grab the new connection.
Socket incomingConnection = this._Server.Accept();
//Send it to the Connection Manager so a Character can be instanced.
ConnectionManager.AddConnection(this._Game, incomingConnection);
}
}
private Socket _Server;
private Thread _ConnectionPool;
private StandardGame _Game;
}
}
[/code]
Connection Manager class <br/>
<pre class="prettyprint using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MudEngine.Game;
using MudEngine.Game.Characters;
namespace MudEngine.Networking
{
public static class ConnectionManager
{
//Collection of currently connected players.
public static List<StandardCharacter> Connections;
/// <summary>
/// Creates a new character for the player and sets it up on the server.
/// </summary>
/// <param name="game </param>
/// <param name="connection </param>
public static void AddConnection(StandardGame game, Socket connection)
{
//Exception checking.
if (Connections == null)
Connections = new List<StandardCharacter>();
//Instance a new character and provide it with the Socket.
StandardCharacter character = new StandardCharacter(game, connection);
//Add it to the Connections collection
Connections.Add(character);
//Invoke the Characters Server connection method
character.Connect();
}
/// <summary>
/// Removes the specified player character from the server.
/// </summary>
/// <param name="character </param>
public static void RemoveConnection(StandardCharacter character)
{
Connections.Remove(character);
}
/// <summary>
/// Disconnects all of the currently connected clients.
/// </summary>
public static void DisconnectAll()
{
if (Connections == null)
return;
foreach (StandardCharacter character in Connections)
{
character.Disconnect();
}
Connections.Clear();
}
}
}
[/code]
Character class (Connected client) <br/>
<pre class="prettyprint using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MudEngine.GameScripts;
using MudEngine.Core.Interfaces;
using MudEngine.Networking;
namespace MudEngine.Game.Characters
{
public class StandardCharacter : INetworked
{
public StandardGame Game { get; private set; }
public CharacterRoles Role { get; protected set; }
public CharacterStats Stats { get; protected set; }
public String Password { get; private set; }
public Boolean Immovable { get; set; }
//TODO: Add current location to characters
//public IEnvironment CurrentLocation
public StandardCharacter(StandardGame game) : base()
{
this.Game = game;
this.OnConnectEvent += new OnConnectHandler(OnConnect);
}
public StandardCharacter(StandardGame game, Socket connection) : this(game)
{
this._Connection = connection;
this._Reader = new StreamReader(new NetworkStream(this._Connection, false));
this._Writer = new StreamWriter(new NetworkStream(this._Connection, true));
}
internal void ExecuteCommand(string message)
{
//Process commands here.
if (message.ToLower().StartsWith("say"))
{
foreach (StandardCharacter character in ConnectionManager.Connections)
{
character.SendMessage(message.Substring("Say ".Length));
_Writer.Flush();
}
}
}
public void SendMessage(string message)
{
_Writer.WriteLine(message);
//_Writer.Flush();
}
public void Disconnect()
{
Console.WriteLine("Disconnecting...");
//Close our currently open socket.
this._Connection.Close();
//Remove this character from the Connection Manager
ConnectionManager.RemoveConnection(this);
Console.WriteLine("Disconnect Complete.");
//Stop the Update() thread.
this._LoopThread.Abort();
}
public void Connect()
{
_LoopThread = new Thread(Update);
_LoopThread.Start();
//_Writer.WriteLine("");
//OnConnectEvent();
}
public void Update()
{
try
{
while (this.Game.Enabled)
{
_Writer.Flush();
String line = _Reader.ReadLine();
ExecuteCommand(line);
}
}
catch
{
}
finally
{
this.Disconnect();
}
}
String CleanString(string line)
{
if ((!String.IsNullOrEmpty(line)) && (line.Length > 0))
{
System.Text.StringBuilder sb = new System.Text.StringBuilder(line.Length);
foreach (char c in line)
{
if (char.IsSymbol(c)) continue;
sb.Append(char.IsControl(c) ? : c);
}
//String newLine = sb.ToString().Trim().Substring(2);
return sb.ToString();
}
else
return String.Empty;
}
public delegate void OnConnectHandler();
public event OnConnectHandler OnConnectEvent;
public void OnConnect()
{
_Writer.WriteLine("Welcome to the sample server!");
}
private Socket _Connection;
private Thread _LoopThread;
private StreamReader _Reader;
private StreamWriter _Writer;
}
}
[/code]
<br/>
The Logger calls only send a Console.WriteLine() message to the console. The CharacterStats and CharacterRole Properties in StandardCharacter are not used anywhere.
Thanks in advance for any help! Ive been stuck with this bug for the last day now and cant get it figured out!
Johnathon <hr class="sig Follow me on Twitter: http://twitter.com/scionwest Project Manager: Mud Designer http://MudDesigner.Codeplex.com
View the full article
Sorry for the long Title, but I wasnt to sure how to properly sum up the issue that I am currently facing.
At the moment I have a working Telnet server. It listens for incoming connections and for each new connection, it passes the Socket off to a Connection Manager class that manages all of the servers current connections. The Connection Manager
class instances a new Character class and provides it with a reference to the Socket so that it may communicate with the server. Im using a StreamReader and StreamWriter attached to the NetworkStream to send and receive user input. This doesnt
seem to be working properly with how I have it implemented.
When a user types the phrase "Say hello" I am removing "Say " and then looping through all of the current connections in the Connection Manager (which is static) and sending the content of the messages to each connected client. However on all of my
connected telnet clients, the message never gets sent or received. Im not sure if this is a multi-thread issue or if Im not using the streams correctly.
Any help would be greatly appreciated! I believe Ive included all of the code youd need to compile the code. The server is started with a new Instance of the Server class and then invoking the Server.Start() method.
Server Class
<pre class="prettyprint using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MudEngine.Core;
using MudEngine.Core.Interfaces;
using MudEngine.Game;
using MudEngine.Game.Characters;
namespace MudEngine.Networking
{
[Category("Networking")]
public class Server
{
[Category("Networking")]
[Description("The name of this server")]
public String Name { get; set; }
[Category("Networking")]
public Int32 Port { get; set; }
[Category("Networking")]
[Description("The Message Of The Day that is presented to users when they connect.")]
public String MOTD { get; set; }
[Category("Networking")]
[Description("Maximum number of people that can connect and play on this server at any time.")]
public Int32 MaxConnections { get; set; }
[Category("Networking")]
[Description("Maximum number of poeple that can be queued for connection.")]
public Int32 QueuedConnectionLimit { get; set; }
[Browsable(false)]
public Boolean Enabled { get; private set; }
/// <summary>
/// Sets up a server on the specified port.
/// </summary>
/// <param name="port </param>
/// <param name="maxConnections </param>
public Server(Int32 port)
{
Logger.WriteLine("Initializing Mud Server Settings");
this.Port = port;
this.MaxConnections = 50;
this.QueuedConnectionLimit = 20;
this.Name = "New Server";
this._Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._Server.Bind(new IPEndPoint(IPAddress.Any, this.Port));
}
/// <summary>
/// Starts the game server. It will listen on a different thread of incoming connections
/// </summary>
public void Start(StandardGame game)
{
//Start the server.
Logger.WriteLine("Starting Mud Server.");
//Start listening for connections
this._Server.Listen(this.QueuedConnectionLimit);
//Launch the new connections listener on a new thread.
this._ConnectionPool = new Thread(AcceptConnection);
this._ConnectionPool.Start();
//Flag the server as enabled.
this.Enabled = true;
//Save a reference to the currently active game
this._Game = game;
Logger.WriteLine("Server started.");
}
public void Stop()
{
//Flag the server as disabled.
this.Enabled = false;
//Stop the thread from listening for accepting new conections
this._ConnectionPool.Abort();
//Disconnect all of the currently connected clients.
ConnectionManager.DisconnectAll();
//Stop the server.
this._Server.Close();
}
private void AcceptConnection()
{
//While the server is enabled, constantly check for new connections.
while (this.Enabled)
{
//Grab the new connection.
Socket incomingConnection = this._Server.Accept();
//Send it to the Connection Manager so a Character can be instanced.
ConnectionManager.AddConnection(this._Game, incomingConnection);
}
}
private Socket _Server;
private Thread _ConnectionPool;
private StandardGame _Game;
}
}
[/code]
Connection Manager class <br/>
<pre class="prettyprint using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MudEngine.Game;
using MudEngine.Game.Characters;
namespace MudEngine.Networking
{
public static class ConnectionManager
{
//Collection of currently connected players.
public static List<StandardCharacter> Connections;
/// <summary>
/// Creates a new character for the player and sets it up on the server.
/// </summary>
/// <param name="game </param>
/// <param name="connection </param>
public static void AddConnection(StandardGame game, Socket connection)
{
//Exception checking.
if (Connections == null)
Connections = new List<StandardCharacter>();
//Instance a new character and provide it with the Socket.
StandardCharacter character = new StandardCharacter(game, connection);
//Add it to the Connections collection
Connections.Add(character);
//Invoke the Characters Server connection method
character.Connect();
}
/// <summary>
/// Removes the specified player character from the server.
/// </summary>
/// <param name="character </param>
public static void RemoveConnection(StandardCharacter character)
{
Connections.Remove(character);
}
/// <summary>
/// Disconnects all of the currently connected clients.
/// </summary>
public static void DisconnectAll()
{
if (Connections == null)
return;
foreach (StandardCharacter character in Connections)
{
character.Disconnect();
}
Connections.Clear();
}
}
}
[/code]
Character class (Connected client) <br/>
<pre class="prettyprint using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MudEngine.GameScripts;
using MudEngine.Core.Interfaces;
using MudEngine.Networking;
namespace MudEngine.Game.Characters
{
public class StandardCharacter : INetworked
{
public StandardGame Game { get; private set; }
public CharacterRoles Role { get; protected set; }
public CharacterStats Stats { get; protected set; }
public String Password { get; private set; }
public Boolean Immovable { get; set; }
//TODO: Add current location to characters
//public IEnvironment CurrentLocation
public StandardCharacter(StandardGame game) : base()
{
this.Game = game;
this.OnConnectEvent += new OnConnectHandler(OnConnect);
}
public StandardCharacter(StandardGame game, Socket connection) : this(game)
{
this._Connection = connection;
this._Reader = new StreamReader(new NetworkStream(this._Connection, false));
this._Writer = new StreamWriter(new NetworkStream(this._Connection, true));
}
internal void ExecuteCommand(string message)
{
//Process commands here.
if (message.ToLower().StartsWith("say"))
{
foreach (StandardCharacter character in ConnectionManager.Connections)
{
character.SendMessage(message.Substring("Say ".Length));
_Writer.Flush();
}
}
}
public void SendMessage(string message)
{
_Writer.WriteLine(message);
//_Writer.Flush();
}
public void Disconnect()
{
Console.WriteLine("Disconnecting...");
//Close our currently open socket.
this._Connection.Close();
//Remove this character from the Connection Manager
ConnectionManager.RemoveConnection(this);
Console.WriteLine("Disconnect Complete.");
//Stop the Update() thread.
this._LoopThread.Abort();
}
public void Connect()
{
_LoopThread = new Thread(Update);
_LoopThread.Start();
//_Writer.WriteLine("");
//OnConnectEvent();
}
public void Update()
{
try
{
while (this.Game.Enabled)
{
_Writer.Flush();
String line = _Reader.ReadLine();
ExecuteCommand(line);
}
}
catch
{
}
finally
{
this.Disconnect();
}
}
String CleanString(string line)
{
if ((!String.IsNullOrEmpty(line)) && (line.Length > 0))
{
System.Text.StringBuilder sb = new System.Text.StringBuilder(line.Length);
foreach (char c in line)
{
if (char.IsSymbol(c)) continue;
sb.Append(char.IsControl(c) ? : c);
}
//String newLine = sb.ToString().Trim().Substring(2);
return sb.ToString();
}
else
return String.Empty;
}
public delegate void OnConnectHandler();
public event OnConnectHandler OnConnectEvent;
public void OnConnect()
{
_Writer.WriteLine("Welcome to the sample server!");
}
private Socket _Connection;
private Thread _LoopThread;
private StreamReader _Reader;
private StreamWriter _Writer;
}
}
[/code]
<br/>
The Logger calls only send a Console.WriteLine() message to the console. The CharacterStats and CharacterRole Properties in StandardCharacter are not used anywhere.
Thanks in advance for any help! Ive been stuck with this bug for the last day now and cant get it figured out!
Johnathon <hr class="sig Follow me on Twitter: http://twitter.com/scionwest Project Manager: Mud Designer http://MudDesigner.Codeplex.com
View the full article