using System; using System.Collections; using System.Net; using System.Net.Sockets; using System.Text; namespace TcpSock { class TcpSock { int tcpIndx = 0; int tcpByte = 0; // 4mb Buffer (see if there are better ways to initialize a large recieve buffer) byte[] tcpRecv = new byte[4096*1024]; //////////////////////////////////////// public Socket tcpSock; //////////////////////////////////////// public String alias; public int Recv(ref string tcpRead) { tcpByte = tcpSock.Available; if (tcpByte > tcpRecv.Length - tcpIndx) tcpByte = tcpRecv.Length - tcpIndx; tcpByte = tcpSock.Receive(tcpRecv, tcpIndx, tcpByte, SocketFlags.Partial); tcpRead = Encoding.UTF8.GetString (tcpRecv, tcpIndx, tcpByte); tcpIndx += tcpByte; return tcpRead.Length; } public void FlushBuffer() { tcpByte = 0; tcpIndx = 0; tcpRecv = new byte[4096 * 1024]; } public int SendLine(string tcpWrite) { tcpSock.Send(Encoding.UTF8.GetBytes(tcpWrite+"\n")); FlushBuffer(); return 0; } public int Send(string tcpWrite) { tcpSock.Send(Encoding.UTF8.GetBytes(tcpWrite)); FlushBuffer(); return 0; } } class Tcp { static void privateMessage(TcpSock currentClient, String recievedLine, ArrayList Client) { foreach (TcpSock aClientSocket in Client) { if (recievedLine.Substring(3).Trim().StartsWith(aClientSocket.alias)) { String message = recievedLine.Substring(3).Trim().Substring(aClientSocket.alias.Length); aClientSocket.SendLine("[" + currentClient.alias + "]: " + message); currentClient.SendLine("PM > " + aClientSocket.alias + ": " + message); Console.WriteLine("{0} sent {1} a Private Message", currentClient.alias, aClientSocket.alias); } } } static void newNick(TcpSock currentClient, String alias, ArrayList Client) { currentClient.SendLine("You are now called " + alias); foreach (TcpSock aClientSocket in Client) { aClientSocket.SendLine(currentClient.alias + " is now known as " + alias); } currentClient.alias = alias; } static void meMessage(TcpSock currentClient, String message, ArrayList Client) { Console.WriteLine("{0} {1}", currentClient.alias, message); foreach (TcpSock aClientSocket in Client) { aClientSocket.SendLine(currentClient.alias + message); } } static void listUsers(TcpSock currentClient, ArrayList Client) { Console.WriteLine("{0} made a userlist request", currentClient.alias); currentClient.SendLine("Users...:"); foreach (TcpSock aClientSocket in Client) { currentClient.SendLine(aClientSocket.alias); } } static void showHelp(TcpSock currentClient) { currentClient.SendLine("Help..."); currentClient.SendLine("/who ... List connected users"); currentClient.SendLine("/list ... -\"- --\"-- -\"-"); currentClient.SendLine("/nick ... Set your chat nickname"); currentClient.SendLine("/me ... e.g. /me waves sends 'nickname waves'"); Console.WriteLine("{0} requested help.", currentClient.alias); } static void kick(TcpSock currentClient, String recievedLine, ArrayList Client) { foreach (TcpSock aClientSocket in Client) { if (aClientSocket.alias == recievedLine.Substring(5).Trim()) { int idx = Client.IndexOf(aClientSocket); Console.WriteLine("{0} kicked {1}", currentClient.alias, aClientSocket.alias); aClientSocket.SendLine("You were kicked by " + currentClient.alias); currentClient.SendLine("You kicked " + aClientSocket.alias); aClientSocket.tcpSock.Shutdown(SocketShutdown.Both); aClientSocket.tcpSock.Close(); Client.RemoveAt(idx); break; } } } static void clearClientConsole(TcpSock currentClient, String recievedLine, ArrayList Client) { foreach (TcpSock aClientSocket in Client) { if (aClientSocket.alias == recievedLine.Substring(6).Trim()) { int idx = Client.IndexOf(aClientSocket); Console.WriteLine("{0} cleared {1}'s chat log", currentClient.alias, aClientSocket.alias); aClientSocket.Send("&&clr"); currentClient.SendLine("You cleared " + aClientSocket.alias + "'s chat log"); } } } [STAThread] static void Main() { //////////////////////////////////////////////////////////////////////////////////////////// ///class IPHostEntry : Stores information about the Host and is required ///for IPEndPoint. ///class IPEndPoint : Stores information about the Host IP Address and ///the Port number. ///class TcpSock : Invokes the constructor and creates an instance. ///class ArrayList : Stores a dynamic array of Client TcpSock objects. IPHostEntry Iphe = Dns.GetHostEntry(Dns.GetHostName()); IPEndPoint Ipep = new IPEndPoint(Iphe.AddressList[0], 4444); Socket Server = new Socket(Ipep.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); //////////////////////////////////////////////////////////////////////////////////////////// ///Initialize ///Capacity : Maximux number of clients able to connect. ///Blocking : Determines if the Server TcpSock will stop code execution ///to receive data from the Client TcpSock. ///Bind : Binds the Server TcpSock to the Host IP Address and the Port Number. ///Listen : Begin listening to the Port; it is now ready to accept connections. ArrayList Client = new ArrayList(); ArrayList Nicks = new ArrayList(); string recievedLine = null; Client.Capacity = 256; Server.Blocking = false; Server.Bind(Ipep); Server.Listen(32); Console.WriteLine("{0}: listening to port {1}", Dns.GetHostName(), Ipep.Port); //////////////////////////////////////////////////////////////////////////////////////////// ///Main loop ///1. Poll the Server TcpSock; if true then accept the new connection. ///2. Poll the Client TcpSock; if true then receive data from Clients. while (true) { //Accept if (Server.Poll(0, SelectMode.SelectRead)) { int i = Client.Add(new TcpSock()); TcpSock currentClient = ((TcpSock)Client[i]); currentClient.tcpSock = Server.Accept(); currentClient.alias = "Client " + i; currentClient.SendLine("Welcome to the test socket server."); currentClient.SendLine("/help for server commands."); for (int j = 0; j < Client.Count; j++) { TcpSock aClientSocket = ((TcpSock)Client[j]); aClientSocket.SendLine(currentClient.alias + " connected."); } Console.WriteLine("{0} connected.", currentClient.alias); } for (int i = 0; i < Client.Count; i++) { TcpSock currentClient = ((TcpSock)Client[i]); if (currentClient.tcpSock.Poll(0, SelectMode.SelectRead)) { if (currentClient.Recv(ref recievedLine) > 0) { if (!recievedLine.StartsWith("/")) { Console.WriteLine("{0}: {1}", currentClient.alias, recievedLine); foreach (TcpSock aClientSocket in Client) { aClientSocket.Send(currentClient.alias + ": " + recievedLine); } } else { String[] command = recievedLine.Split(new Char[]{' ','\n','\r'}); switch (command[0]) { case "/nick": { newNick(currentClient, recievedLine.Substring(5).Trim(), Client); break; } case "/me": { meMessage(currentClient, recievedLine.Substring(3), Client); break; } case "/who": case "/list": { listUsers(currentClient, Client); break; } case "/help": { showHelp(currentClient); break; } case "/pm": { privateMessage(currentClient, recievedLine, Client); break; } case "/stfu": case "/gtfo": { kick(currentClient, recievedLine, Client); break; } case "/clear": { clearClientConsole(currentClient, recievedLine, Client); break; } default: break; } } } else { currentClient.tcpSock.Shutdown(SocketShutdown.Both); currentClient.tcpSock.Close(); Client.RemoveAt(i); Console.WriteLine("{0} disconnected.", currentClient.alias); foreach (TcpSock aClientSocket in Client) { aClientSocket.Send(currentClient.alias + " disconnected.\n"); } } } } } } } }