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();
  }
}




VB: Imports System.Net.Sockets
Imports System.Text
Imports System.Threading

Module Module1

    Class State
        Private ReadOnly client As TcpClient
        Private ReadOnly sb As New StringBuilder

        Public Sub New(name As String, client As TcpClient)
            Me.Name = name
            Me.client = client
        End Sub

        Public ReadOnly Property Name As String

        Public Sub Send(text As String)
            Dim bytes = Encoding.ASCII.GetBytes(String.Format("{0}" & vbCrLf, text))
            client.GetStream().Write(bytes, 0, bytes.Length)
        End Sub
    End Class

    ReadOnly connections As New Dictionary(Of Integer, State)
    Dim listen As TcpListener
    Dim serverThread As Thread

    Sub Main()
        listen = New TcpListener(Net.IPAddress.Parse("127.0.0.1"), 4004)
        serverThread = New Thread(New ThreadStart(AddressOf DoListen))
        serverThread.Start()
    End Sub

    Private Sub DoListen()
        listen.Start()
        Console.WriteLine("Server: Started server")

        Do
            Console.Write("Server: Waiting...")
            Dim client = listen.AcceptTcpClient()
            Console.WriteLine(" Connected")

            
            Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf DoClient))

            clientThread.Start(client)
        Loop
    End Sub

    Private Sub DoClient(client As TcpClient)
        Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId)
        Dim bytes = Encoding.ASCII.GetBytes("Enter name: ")
        client.GetStream().Write(bytes, 0, bytes.Length)

        Dim done As Boolean
        Dim name As String
        Do
            If Not client.Connected Then
                Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
                client.Close()
                Thread.CurrentThread.Abort() 
            End If

            name = Receive(client)
            done = True

            For Each cl In connections
                Dim state = cl.Value
                If state.Name = name Then
                    bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ")
                    client.GetStream().Write(bytes, 0, bytes.Length)
                    done = False
                End If
            Next
        Loop While Not done

        connections.Add(Thread.CurrentThread.ManagedThreadId, New State(name, client))
        Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
        Broadcast(String.Format("+++ {0} arrived +++", name))

        Do
            Dim text = Receive(client)
            If text = "/quit" Then
                Broadcast(String.Format("Connection from {0} closed.", name))
                connections.Remove(Thread.CurrentThread.ManagedThreadId)
                Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
                Exit Do
            End If

            If Not client.Connected Then
                Exit Do
            End If

            Broadcast(String.Format("{0}> {1}", name, text))
        Loop

        Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
        client.Close()
        Thread.CurrentThread.Abort()
    End Sub

    Private Function Receive(client As TcpClient) As String
        Dim sb As New StringBuilder
        Do
            If client.Available > 0 Then
                While client.Available > 0
                    Dim ch = Chr(client.GetStream.ReadByte())
                    If ch = vbCr Then
                        
                        Continue While
                    End If
                    If ch = vbLf Then
                        Return sb.ToString()
                    End If
                    sb.Append(ch)
                End While

                
                Thread.Sleep(100)
            End If
        Loop
    End Function

    Private Sub Broadcast(text As String)
        Console.WriteLine(text)
        For Each client In connections
            If client.Key <> Thread.CurrentThread.ManagedThreadId Then
                Dim state = client.Value
                state.Send(text)
            End If
        Next
    End Sub

End Module