Yeah I apparently forgot to ask sorry. >.<
What does it take to setup (or get someplace to host) a server (physical not the program) and, what all do I need to know to set up the server program or is what I know fine enough for now?
The networking code that I know at the moment from my server / client console chat program:
// Main code of console chat program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClientTest;
using ServerTest;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace MainProgram
{
class ClientServerTest
{
#region Messages
public static string PMain = "Enter a command: \n\t/C to connect to a server\n\t/H to host a server\n\t/E to quit";
public static string PMInvalid = "Invalid Command. Valid commands are:\n\t/C to connect to a server\n\t/H to host a server\n\t/E to quit";
public static string PQuit = "Enter some text to send, or /q to stop hosting and return to main menu.";
public static string PConnect = "Enter an address to connect to or /C to return: ";
#endregion Messages
public static AsyncClient CLIENT = new AsyncClient();
public static AsyncServer SERVER = new AsyncServer(3);
const int port = 11000;
public static void HostAndRun()
{
IPAddress sip = null;
IPHostEntry ipEntry = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress a in ipEntry.AddressList)
{
if (a.AddressFamily == AddressFamily.InterNetwork)
{
sip = a;
break;
}
}
IPEndPoint ServerEndPoint = new IPEndPoint(sip, port);
SERVER.Host(ServerEndPoint);
CLIENT.Host(ServerEndPoint);
string Feed = string.Empty;
Console.WriteLine(PQuit);
while (!CLIENT.isQuitting)
{
CLIENT.RunClient();
if (!CLIENT.isQuitting)
{
SERVER.RunServer();
}
else
{
CLIENT.StopConnection();
SERVER.StopServer();
}
}
Console.WriteLine(PMain);
}
public static void ConnectAndRun()
{
bool loop = true;
IPAddress ip = null;
string serverIP = string.Empty;
Console.WriteLine(PConnect);
while (loop)
{
serverIP = Console.ReadLine();
switch (serverIP.ToUpper())
{
case "/C":
loop = false;
serverIP = string.Empty;
break;
default:
if (serverIP != string.Empty)
{
try
{
ip = IPAddress.Parse(serverIP);
loop = false;
}
catch (FormatException fe)
{
Console.WriteLine("Invalid address\n");
Console.WriteLine(PConnect);
serverIP = string.Empty;
loop = true;
}
}
break;
}
}
if (serverIP != string.Empty)
{
IPEndPoint remoteEP = new IPEndPoint(ip, port);
CLIENT.Start(remoteEP);
}
CLIENT.StopConnection();
Console.WriteLine(PMain);
}
public static void Run()
{
bool loop = true;
string command = string.Empty;
Console.WriteLine(PMain);
while (loop)
{
command = Console.ReadLine();
switch (command.ToUpper())
{
case "/C":
ConnectAndRun();
break;
case "/H":
HostAndRun();
break;
case "/E":
loop = false;
break;
default:
Console.WriteLine(PMInvalid);
break;
}
}
}
public static int Main(string[] args)
{
Console.Title = "ClientServer Test Program";
Run();
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
return 0;
}
}
}
// Misc code for console chat program
using System;
using System.Net;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Threading;
namespace MiscStuff
{
public enum ReasonForQuit
{
Default = 0, ServerFull = 1
}
class BufferSpace
{
public const int BufferSize = 512;
}
public class QuitReason
{
public static string CloseReason(ReasonForQuit reason = ReasonForQuit.Default)
{
string output = string.Empty;
switch (reason)
{
case ReasonForQuit.Default:
break;
case ReasonForQuit.ServerFull:
output = "<#Reason#>:FULL";
break;
}
return output;
}
}
// State object for reading client data asynchronously
public class Client
{
// Client socket.
public byte[] readBuffer = new byte[BufferSpace.BufferSize];
public byte[] writeBuffer = new byte[BufferSpace.BufferSize];
private Socket Socket = null;
public Socket clientSocket
{
get { return Socket; }
set { Socket = value; }
}
//create a network stream for easier access
private NetworkStream outStream;
public NetworkStream WriteFeed
{
get { return outStream; }
}
//use a stream reader because of ReadLine() method
private NetworkStream inStream;
public NetworkStream ReadFeed
{
get { return inStream; }
}
public bool toRemove = false;
public string feedBack = string.Empty;
public StringBuilder sb = new StringBuilder();
public IPEndPoint ID;
public Client(Socket s)
{
if (s != null)
{
Socket = s;
ID = (IPEndPoint)s.RemoteEndPoint;
outStream = new NetworkStream(s);
inStream = new NetworkStream(s);
}
}
public void Set(Socket s)
{
Socket = s;
if (s != null)
{
ID = (IPEndPoint)s.RemoteEndPoint;
outStream = new NetworkStream(s);
inStream = new NetworkStream(s);
}
}
}
}
// client code for console chat program
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using MiscStuff;
namespace ClientTest
{
using qr = MiscStuff.QuitReason;
public class AsyncClient
{
#region Messages
public string PFConnect = "Failed to connect to server.\nType /R to try connecting again or type /C to return to main.";
public string PFInvald = "Invalid Command. Type /R to try connecting again or type /C to return to main.";
public static string PDC = "Enter some text to send, or /q to disconnect and return to main menu.";
public static string PConnected = "Connected to the server.\n";
#endregion Messages
private int ConTryTimeOut = 6000;
private Client ThisClient = new Client(null);
private string Feed = string.Empty;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone;
private static ManualResetEvent sendDone;
private static ManualResetEvent receiveDone;
private static ManualResetEvent disconnetDone;
private static ManualResetEvent issueCheckDone;
private bool Started;
private bool AttempingCon;
private bool Quit;
public bool isQuitting
{
get { return Quit; }
}
private bool Hosting = false;
private IPEndPoint ID;
public AsyncClient()
{
}
private void SetupClientSocket()
{ // Resolving local machine information
ThisClient.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void Reset()
{
connectDone = new ManualResetEvent(false);
sendDone = new ManualResetEvent(false);
receiveDone = new ManualResetEvent(false);
disconnetDone = new ManualResetEvent(false);
issueCheckDone = new ManualResetEvent(false);
AttempingCon = false;
Started = false;
Quit = false;
}
public void Start(IPEndPoint id)
{
Reset();
ID = id;
Hosting = false;
StartConnection();
CheckForIssues();
while (AttempingCon)
{
if (AttempingCon)
{
Console.WriteLine(PFConnect);
}
AttemptConnect();
}
if (Started)
{
Console.WriteLine(PConnected);
Console.WriteLine(PDC);
while (!Quit)
{
RunClient();
}
}
}
public void RunClient()
{
if (Connected(ThisClient.clientSocket))
{
if (Console.KeyAvailable)
{
Feed = Console.ReadLine();
if (Feed.ToUpper() == "/Q")
{
if (!Hosting)
{
Disconnect();
disconnetDone.WaitOne();
}
Quit = true;
Feed = string.Empty;
}
else if (Feed != string.Empty)
{
Feed += "<EOF>";
}
}
ProcessConnection();
}
else
{
ServerClosed();
}
}
public void Host(IPEndPoint self)
{
Reset();
Hosting = true;
ID = self;
if (ThisClient.clientSocket == null)
{
SetupClientSocket();
}
ThisClient.clientSocket.BeginConnect(ID, new AsyncCallback(ConnectCallback), ThisClient.clientSocket);
connectDone.WaitOne();
}
private void ProcessConnection()
{
//what I want it to do is read asynchronously if data is available, and write the data asynchronously to the client after reading is done, and if the
//client is closing or disconnecting, it will close the client's connection.
if (!Quit)
{
if (!Connected(ThisClient.clientSocket) && ThisClient.clientSocket != null)
{
ServerClosed();
}
else
{
if (Feed != string.Empty)
{
Send(ThisClient, Feed);
sendDone.WaitOne(100);
sendDone.Reset();
}
if (ThisClient.ReadFeed.DataAvailable)
{
Receive();
receiveDone.WaitOne(100);
receiveDone.Reset();
}
Feed = string.Empty;
}
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
ThisClient.Set(client);
// Signal that the connection has been made.
connectDone.Set();
AttempingCon = false;
Started = true;
}
catch (Exception e)
{
Console.WriteLine("The server is not responding.\n");
AttempingCon = true;
Started = false;
//Console.WriteLine(e.ToString());
}
}
private void ConnectIssueCallback(IAsyncResult result)
{
if (Connected(ThisClient.clientSocket))
{
try
{
Client state = (Client)result.AsyncState;
NetworkStream handler = state.ReadFeed;
state.feedBack = string.Empty;
int bytesRead = handler.EndRead(result);
state.sb.Append(Encoding.ASCII.GetString(state.readBuffer, 0, bytesRead));
state.feedBack = state.sb.ToString();
if (state.feedBack == qr.CloseReason(ReasonForQuit.ServerFull))
{ //data transfer done
state.sb.Clear();
issueCheckDone.Set();
Console.WriteLine("Can't connect to the server. Server is full.");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
private void Receive()
{
if (Connected(ThisClient.clientSocket))
{
try
{
// Begin receiving the data from the remote device.
ThisClient.ReadFeed.BeginRead(ThisClient.readBuffer, 0, BufferSpace.BufferSize,
new AsyncCallback(ReadStream), ThisClient);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
private void ReadStream(IAsyncResult result)
{
if (Connected(ThisClient.clientSocket))
{
try
{
Client state = (Client)result.AsyncState;
NetworkStream handler = state.ReadFeed;
state.feedBack = string.Empty;
int bytesRead = handler.EndRead(result);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.readBuffer, 0, bytesRead));
state.feedBack = state.sb.ToString();
if (state.feedBack.IndexOf("<EOF>") > -1)
{ //data transfer done
string temp = state.feedBack.Remove(state.feedBack.Length - 5, 5);
state.feedBack = temp;
//Console.WriteLine("Recieved {0} bytes from {1}:{2}. Message: {3}", state.feedBack.Length, state.ID.Address,
//state.ID.Port, state.feedBack);
Console.WriteLine("Recieved message from {0}:{1}. Message: {2}", state.ID.Address,
state.ID.Port, state.feedBack);
state.sb.Clear();
receiveDone.Set();
}
else
{ //not all data sent
handler.BeginRead(state.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ReadStream), state);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
private void WriteStream(IAsyncResult result)
{
if (Connected(ThisClient.clientSocket))
{
try
{
// Retrieve the socket from the state object.
Client state = (Client)result.AsyncState;
NetworkStream handler = state.WriteFeed;
// Complete sending the data to the remote device.
handler.EndWrite(result);
sendDone.Set();
Feed = string.Empty;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
private void Send(Client c, string data)
{
if (Connected(ThisClient.clientSocket))
{
try
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
c.WriteFeed.BeginWrite(byteData, 0, byteData.Length, new AsyncCallback(WriteStream), c);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
public void AttemptConnect()
{
string i = string.Empty;
i = Console.ReadLine();
switch (i.ToUpper())
{
case "/R":
Console.WriteLine("Attempting to connect to the server...\n");
StartConnection();
break;
case "/C":
Console.WriteLine("Returning to Main...\n");
AttempingCon = false;
break;
default:
Console.WriteLine(PFInvald);
break;
}
i = string.Empty;
}
private void StartConnection()
{
if (ThisClient.clientSocket == null)
{
SetupClientSocket();
}
ThisClient.clientSocket.BeginConnect(ID, new AsyncCallback(ConnectCallback), ThisClient.clientSocket);
connectDone.WaitOne(ConTryTimeOut);
}
private void CheckForIssues()
{
if (Connected(ThisClient.clientSocket))
{
if (ThisClient.ReadFeed.DataAvailable)
{
ThisClient.ReadFeed.BeginRead(ThisClient.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ConnectIssueCallback), ThisClient);
Started = false;
Quit = true;
issueCheckDone.WaitOne();
}
}
}
private bool Connected(Socket s)
{
if (s != null)
{
return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
}
return false;
}
private void Disconnect()
{
try
{
ThisClient.clientSocket.BeginDisconnect(false, new AsyncCallback(DisconnectCallBack), ThisClient);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ServerClosed()
{
if (!Hosting)
{
Console.WriteLine("Server connection stopped. Returning to main...\n");
}
ThisClient.ReadFeed.Close();
ThisClient.WriteFeed.Close();
if (ThisClient.clientSocket != null)
{
ThisClient.clientSocket.Close();
}
ThisClient.Set(null);
Quit = true;
}
private void DisconnectCallBack(IAsyncResult result)
{
try
{
Client c = (Client)result.AsyncState;
c.clientSocket.EndDisconnect(result);
c.WriteFeed.Close();
c.ReadFeed.Close();
c.clientSocket.Close();
c.Set(null);
Console.WriteLine("Disconnected from the server. Returning to main...\n");
disconnetDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void StopConnection()
{
if (ThisClient.clientSocket != null)
{
if (ThisClient.clientSocket.Connected)
{
ThisClient.WriteFeed.Close();
ThisClient.ReadFeed.Close();
ThisClient.clientSocket.Close();
}
connectDone.Close();
sendDone.Close();
receiveDone.Close();
disconnetDone.Close();
issueCheckDone.Close();
}
ThisClient.clientSocket = null;
}
}
}
// server code for console chat program
using System;
using System.Net;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Threading;
using MiscStuff;
namespace ServerTest
{
using qr = MiscStuff.QuitReason;
public class AsyncServer
{
private Socket serverSocket;
private int maxConnections = 0;
private List<Client> connections;
private int endedConnections = 0;
private bool AttemptingAccept = false;
public AsyncServer(int maxC)
{
maxConnections = maxC;
}
private void SetupServerSocket(IPEndPoint id)
{ // Resolving local machine information
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(id);
serverSocket.Listen(100);
Console.WriteLine("Hosting started");
}
public void Start(IPEndPoint id)
{
connections = new List<Client>();
AttemptingAccept = false;
SetupServerSocket(id);
}
public void RunServer()
{
if (!AttemptingAccept)
{
AttemptingAccept = true;
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
}
ProcessConnections();
}
public void Host(IPEndPoint ip)
{
Start(ip);
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
}
private void ProcessConnections()
{
// process the connections and then remove ones that are to be closed from dcing or because the server is full.
lock (connections)
{
foreach (Client c in connections)
{
if (!c.toRemove)
{
if (!Connected(c.clientSocket))
{
CloseConnection(c); // sets a connection to close after all connections have been processed.
}
else
{
if (c.ReadFeed.DataAvailable)
{
c.ReadFeed.BeginRead(c.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ReadStream), c);
}
}
}
}
}
if (endedConnections > 0)
{
for (int i = 0; i < connections.Count; i++)
{
if (connections[i].toRemove)
{
connections.RemoveAt(i);
}
}
endedConnections = 0;
}
}
private void AcceptCallback(IAsyncResult result)
{
try
{
// Finish Accept
Socket s = (Socket)result.AsyncState;
Client ConTest = new Client(null);
ConTest.Set(s.EndAccept(result));
if (ConTest.clientSocket != null)
{
AttemptingAccept = false;
if (connections.Count == maxConnections) //server is full send a message to the client that its full so it can notify the user that its full
{
string reason = qr.CloseReason(ReasonForQuit.ServerFull);
Send(ConTest, reason);
Console.WriteLine("Client {0}:{1} tried to connnect but the server is full.", ConTest.ID.Address, ConTest.ID.Port);
}
else // server isn't full continue as normal
{
lock (connections)
{
connections.Add(ConTest);
}
Console.WriteLine("Client {0}:{1} connected. Total connected clients {2}", ConTest.ID.Address, ConTest.ID.Port, connections.Count);
}
}
}
catch (Exception exc)
{
}
}
private void ReadStream(IAsyncResult result)
{
try
{
Client state = (Client)result.AsyncState;
NetworkStream handler = state.ReadFeed;
state.feedBack = string.Empty;
int bytesRead = handler.EndRead(result);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.readBuffer, 0, bytesRead));
state.feedBack = state.sb.ToString();
if (state.feedBack.IndexOf("<EOF>") > -1)
{ //data transfer done
lock (connections)
{
foreach (Client c in connections)
{
if (TestForSend(c))
{
Send(c, state.feedBack);
}
}
}
state.sb.Clear();
}
else
{ //not all data sent
handler.BeginRead(state.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ReadStream), state);
}
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
private bool TestForSend(Client c)
{
return (!c.toRemove && Connected(c.clientSocket));
}
private void WriteStream(IAsyncResult result)
{
try
{
// Retrieve the socket from the state object.
Client state = (Client)result.AsyncState;
NetworkStream handler = state.WriteFeed;
// Complete sending the data to the remote device.
handler.EndWrite(result);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void Send(Client c, string data)
{
try
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
c.WriteFeed.BeginWrite(byteData, 0, byteData.Length, new AsyncCallback(WriteStream), c);
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
private bool Connected(Socket s)
{
if (s != null)
{
return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
}
return false;
}
private void CloseConnection(Client c)
{
try
{
if (c.clientSocket != null)
{
c.WriteFeed.Close();
c.ReadFeed.Close();
c.clientSocket.Close();
c.toRemove = true;
++endedConnections;
Console.WriteLine("Client {0}:{1} disconnected. Total connected clients {2}", c.ID.Address, c.ID.Port, connections.Count - endedConnections);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void StopServer()
{
foreach (Client c in connections)
{
c.WriteFeed.Close();
c.ReadFeed.Close();
c.clientSocket.Close();
}
connections.Clear();
serverSocket.Close();
serverSocket = null;
Console.WriteLine("Hosting stopped. Returning to main...\n");
}
}
}