Spielprogrammierung mit Java
HomeAufgabenDruckenJava-Online

TCP Chat

Chat ist die einfachste Anwendung einer TCP/IP-Kommunikation. Unser TCPChat ermöglicht zwei oder mehreren Personen, die sich im gleichen Chatraum (mit der gleichen SessionID) anmelden, zu kommunizieren. Die Verwaltung der Session ID's übernimmt unser TcpRelay Server, der ebenfalls dafür sorgt, dass alle Daten über den Port 80 versendet und empfangen und somit nicht von Firewalls aufgehalten werden.




Chat starten

Die beiden Chatpartner starten den Chat mit dem oben stehenden Link. Nach der Eingabe einer Session ID und eines Nicknamens können die Mitteilungen im mittleren Feld eingegeben werden. Im oberen Fenster erscheinen alle Mitteilungen.

Zum Testen können Sie die Applikation auch zweimal auf dem gleichen Computer starten.

Beispiel im Online-Editor bearbeiten

Programmcode für lokale Bearbeitung downloaden: ChatClient.zip

Erklärungen zum Programmcode:

initGUI()
Die grafische Benutzeroberfläche (GUI) wird mit javax Swing Elementen gestaltet und besteht im wesentlichen aus:
- outputArea: Text zum versenden (Chat Mitteilung)
- inputArea: Empfangener Text. Hier werden alle Mitteilungen nacheinander aufgelistet
-statusArea: Zeigt, welche ChatClients online sind
tcpNode.connect(id, nickname)
Verbindet den tcpNode mit der eingegebner SessionID und Nickname

if (evt.getKeyCode() == KeyEvent.VK_ENTER)
{
   tcpNode.sendMessage(line);
   messageReceived(nickname, line);
}

Mit Enter-Taste wird die Texteingabe versendet

public void messageReceived(String sender, String text)
{
   append(inputArea, sender + ":--> " + text);
}
Nachricht empfangen und anzeigen
nodeStateChanged()

Gibt den Verbindungsstatus der ChatClients an

Programmcode:

// ChatClient.java

import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import ch.aplu.tcp.*;

public class ChatClient extends JFrame implements KeyListenerTcpNodeListener
{
  private static final String sessionID = "room1";
  private static final String defaultNickname = "Max";
  private String nickname;
  private String line = "";
  private JPanel contentPane;
  private JPanel textPanel = new JPanel();
  private JPanel controlPanel = new JPanel();
  private JTextArea inputArea = new JTextArea(20, 40);
  private JScrollPane inputScrollPane = new JScrollPane(inputArea,
    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  private JTextArea outputArea = new JTextArea(3, 40);
  private JScrollPane outputScrollPane = new JScrollPane(outputArea,
    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  private JTextArea statusArea = new JTextArea(5, 40);
  private JScrollPane statusScrollPane = new JScrollPane(statusArea,
    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  private JButton connectBtn = new JButton("Connect      ");
  private JTextField sessionEntry = new JTextField(10);
  private JLabel sessionLbl = new JLabel("SessionID:");
  private JTextField nicknameEntry = new JTextField(10);
  private JLabel nicknameLbl = new JLabel("Nickname:");
  private ChatClient chatClient;
  private TcpNode tcpNode;

  public ChatClient()
  {
    super("Chat Client");
    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    initGUI();
    initActions();
    pack();
    setLocation(10, 10);
    setVisible(true);
    chatClient = this;
    statusArea.setText("Enter room and nickname, then click on \"connect\". ");
  }

  private void initGUI()
  {
    setResizable(false);
    contentPane = (JPanel)getContentPane();
    contentPane.setLayout(new BorderLayout());

    textPanel.setLayout(new BorderLayout());
    textPanel.add(outputScrollPane, BorderLayout.CENTER);
    textPanel.add(inputScrollPane, BorderLayout.NORTH);
    textPanel.add(statusScrollPane, BorderLayout.SOUTH);

    sessionEntry.setText(sessionID);
    nicknameEntry.setText(defaultNickname);
    controlPanel.add(connectBtn);
    controlPanel.add(sessionLbl);
    controlPanel.add(sessionEntry);
    controlPanel.add(nicknameLbl);
    controlPanel.add(nicknameEntry);

    contentPane.add(textPanel, BorderLayout.NORTH);
    contentPane.add(controlPanel, BorderLayout.SOUTH);
    inputArea.setEditable(false);
    statusArea.setEditable(false);
    outputArea.addKeyListener(this);
    setOutputEnabled(false);
  }

  private void initActions()
  {
    connectBtn.addActionListener(new ActionListener()
    {

      public void actionPerformed(ActionEvent evt)
      {
        if (tcpNode == null)
        {
          inputArea.setText("");
          outputArea.setText("");
          statusArea.setText("");
          String id = sessionEntry.getText().trim();
          nickname = nicknameEntry.getText().trim();
          if (nickname.length() < 3)
          {
            statusArea.setText("Illegal nickname (>2 ASCII chars required).");

            return;
          }
          connectBtn.setEnabled(false);
          int port = 80;
          tcpNode = new TcpNode();
          tcpNode.addTcpNodeListener(chatClient);
          append(statusArea, "Trying to connect to host '"
            + tcpNode.getRelay(+ "' (port: "
            + tcpNode.getPort(+ ") using nickname "
            + nickname + "...");

          tcpNode.connect(id, nickname);
        }
        else
        {
          tcpNode.disconnect();
          tcpNode = null;
        }
      }
    });
  }

  public void append(final JTextArea area, final String text,
    final boolean eol)
  {
    EventQueue.invokeLater(new Runnable()
    {

      public void run()
      {
        area.append(text);
        if (eol)
          area.append("\n");
        scrollToEnd(area);
      }
    });
  }

  public void append(final JTextArea area, final String text)
  {
    append(area, text, true);
  }

  public void setOutputEnabled(boolean enable)
  {
    outputArea.setEnabled(enable);
    if (enable)
      outputArea.requestFocus();
  }

  private void scrollToEnd(JTextArea ta)
  {
    try
    {
      ta.setCaretPosition(ta.getLineEndOffset(ta.getLineCount() - 1));
    }
    catch (BadLocationException ex)
    {
      append(statusArea, ex.toString());
    }
  }

  public void keyPressed(KeyEvent evt)
  {
    if (evt.getKeyCode() == KeyEvent.VK_ENTER) // enter -> send data
    {
      tcpNode.sendMessage(line);
      messageReceived(nickname, line);
      line = "";
      outputArea.setText("")
      evt.consume(); 
    }
    else
    {
      char ch;
      if (evt.getKeyCode() == && line.length() > 0) // backspace
        line = line.substring(0, line.length() - 1);
      else
      {
        if (evt.getKeyCode() == || evt.getKeyCode() > 31)
        {
          ch = evt.getKeyChar();
          line += ch;
        }
      }
    }

  }

  public void keyReleased(KeyEvent evt)
  {
  }

  public void keyTyped(KeyEvent evt)
  {
  }

  public void messageReceived(String sender, String text)
  {
    append(inputArea, sender + ":--> " + text);
  }

  public void statusReceived(String text)
  {
    append(statusArea, text);
  }

  public void nodeStateChanged(TcpNodeState state)
  {
    switch (state)
    {
      case DISCONNECTED:
        append(statusArea, "Connection broken.");
        connectBtn.setText("Connect     ");
        connectBtn.setEnabled(true);
        tcpNode = null;
        setOutputEnabled(false);
        break;
      case CONNECTING:
        append(statusArea, "Connection underway...");
        break;
      case CONNECTED:
        append(statusArea, "Connection established.");
        connectBtn.setText("Disconnect");
        connectBtn.setEnabled(true);
        setOutputEnabled(true);
        outputArea.setText("Type message here, then send it by pressing enter");
        outputArea.selectAll();
        break;
    }
  }

  public static void main(String[] args)
  {
    EventQueue.invokeLater(new Runnable()
    {

      public void run()
      {
        new ChatClient();
      }
    });
  }
}