Task: Chat server





Java: import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer implements Runnable
{
  private int port = 0;
  private List<Client> clients = new ArrayList<Client>();
  
  public ChatServer(int port)
  {  this.port = port;  }
  
  public void run()
  {
    try
    {
      ServerSocket ss = new ServerSocket(port);
      while (true)
      {
        Socket s = ss.accept();
        new Thread(new Client(s)).start();
      }
    }
    catch (Exception e)
    {  e.printStackTrace();  }
  }

  private synchronized boolean registerClient(Client client)
  {
    for (Client otherClient : clients)
      if (otherClient.clientName.equalsIgnoreCase(client.clientName))
        return false;
    clients.add(client);
    return true;
  }

  private void deregisterClient(Client client)
  {
    boolean wasRegistered = false;
    synchronized (this)
    {  wasRegistered = clients.remove(client);  }
    if (wasRegistered)
      broadcast(client, "--- " + client.clientName + " left ---");
  }
  
  private synchronized String getOnlineListCSV()
  {
    StringBuilder sb = new StringBuilder();
    sb.append(clients.size()).append(" user(s) online: ");
    for (int i = 0; i < clients.size(); i++)
      sb.append((i > 0) ? ", " : "").append(clients.get(i).clientName);
    return sb.toString();
  }
  
  private void broadcast(Client fromClient, String msg)
  {
    
    List<Client> clients = null;
    synchronized (this)
    {  clients = new ArrayList<Client>(this.clients);  }
    for (Client client : clients)
    {
      if (client.equals(fromClient))
        continue;
      try
      {  client.write(msg + "\r\n");  }
      catch (Exception e)
      {  }
    }
  }

  public class Client implements Runnable
  {
    private Socket socket = null;
    private Writer output = null;
    private String clientName = null;
    
    public Client(Socket socket)
    {
      this.socket = socket;
    }
    
    public void run()
    {
      try
      {
        socket.setSendBufferSize(16384);
        socket.setTcpNoDelay(true);
        BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        output = new OutputStreamWriter(socket.getOutputStream());
        write("Please enter your name: ");
        String line = null;
        while ((line = input.readLine()) != null)
        {
          if (clientName == null)
          {
            line = line.trim();
            if (line.isEmpty())
            {
              write("A name is required. Please enter your name: ");
              continue;
            }
            clientName = line;
            if (!registerClient(this))
            {
              clientName = null;
              write("Name already registered. Please enter your name: ");
              continue;
            }
            write(getOnlineListCSV() + "\r\n");
            broadcast(this, "+++ " + clientName + " arrived +++");
            continue;
          }
          if (line.equalsIgnoreCase("/quit"))
            return;
          broadcast(this, clientName + "> " + line);
        }
      }
      catch (Exception e)
      {  }
      finally
      {
        deregisterClient(this);
        output = null;
        try
        {  socket.close();  }
        catch (Exception e)
        {  }
        socket = null;
      }
    }
    
    public void write(String msg) throws IOException
    {
      output.write(msg);
      output.flush();
    }
    
    public boolean equals(Client client)
    {
      return (client != null) && (client instanceof Client) && (clientName != null) && (client.clientName != null) && clientName.equals(client.clientName);
    }
  }
  
  public static void main(String[] args)
  {
    int port = 4004;
    if (args.length > 0)
      port = Integer.parseInt(args[0]);
    new ChatServer(port).run();
  }
}







Ada: with Ada.Containers.Vectors;
with Ada.Command_Line; use Ada.Command_Line;
with Ada.Exceptions;   use Ada.Exceptions;
with Ada.Text_IO;      use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Sockets;          use Sockets;

procedure Chat_Server is

   package Client_Vectors is new Ada.Containers.Vectors
     (Element_Type => Socket_FD, Index_Type => Positive);
   All_Clients : Client_Vectors.Vector;

   procedure Write (S : String) is
      procedure Output (Position : Client_Vectors.Cursor) is
         Sock : Socket_FD := Client_Vectors.Element (Position);
      begin
         Put_Line (Sock, S);
      end Output;
   begin
      All_Clients.Iterate (Output'Access);
   end Write;

   task type Client_Task is
      entry Start (FD : Socket_FD);
   end Client_Task;

   task body Client_Task is
      Sock    : Socket_FD;
      Sock_ID : Positive;
      Name    : Unbounded_String;
   begin
      select
         accept Start (FD : Socket_FD) do
            Sock := FD;
         end Start;
      or
         terminate;
      end select;

      while Name = Null_Unbounded_String loop
         Put (Sock, "Enter Name:");
         Name := To_Unbounded_String (Get_Line (Sock));
      end loop;
      Write (To_String (Name) & " joined.");
      All_Clients.Append (Sock);
      Sock_ID := All_Clients.Find_Index (Sock);
      loop
         declare
            Input : String := Get_Line (Sock);
         begin
            Write (To_String (Name) & ": " & Input);
         end;
      end loop;
   exception
      when Connection_Closed =>
         Put_Line ("Connection closed");
         Shutdown (Sock, Both);
         All_Clients.Delete (Sock_ID);
         Write (To_String (Name) & " left.");
   end Client_Task;

   Accepting_Socket : Socket_FD;
   Incoming_Socket  : Socket_FD;

   type Client_Access is access Client_Task;
   Dummy : Client_Access;
begin
   if Argument_Count /= 1 then
      Raise_Exception (Constraint_Error'Identity,
                       "Usage: " & Command_Name & " port");
   end if;
   Socket (Accepting_Socket, PF_INET, SOCK_STREAM);
   Setsockopt (Accepting_Socket, SOL_SOCKET, SO_REUSEADDR, 1);
   Bind (Accepting_Socket, Positive'Value (Argument (1)));
   Listen (Accepting_Socket);
   loop
      Put_Line ("Waiting for new connection");
      Accept_Socket (Accepting_Socket, Incoming_Socket);
      Put_Line ("New connection acknowledged");

      Dummy := new Client_Task;
      Dummy.Start (Incoming_Socket);
   end loop;
end Chat_Server;