# Java Chat Server



## SteinAdler5 (29. Jul 2016)

Hallo kann mir jemand diesen code so abändern das es ohne gui gestartet wird?
Ich möchte diesen Chat Server nämlich auf meinem vserver nutzen können.

Main Klasse:
* ServerFrame.java*

```
package de.steinadler5.socket;
import java.awt.Color;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.UIManager;
@SuppressWarnings("serial")
public class ServerFrame extends javax.swing.JFrame {
    public SocketServer server;
    public Thread serverThread;
    public String filePath = "D:/Data.xml";
    public JFileChooser fileChooser;
    public ServerFrame() {
        initComponents();    
        jTextField3.setEditable(false);
        jTextField3.setBackground(Color.WHITE);
        fileChooser = new JFileChooser();
        jTextArea1.setEditable(false);
    }
    public boolean isWin32(){
        return System.getProperty("os.name").startsWith("Windows");
    }
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        jButton1 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jLabel3 = new javax.swing.JLabel();
        jTextField3 = new javax.swing.JTextField();
        jButton2 = new javax.swing.JButton();
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Server");
        jButton1.setText("Start Server");
        jButton1.setEnabled(false);
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        jTextArea1.setColumns(20);
        jTextArea1.setFont(new java.awt.Font("Consolas", 0, 12)); // NOI18N
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);
        jLabel3.setText("Datenbank Datei: ");
        jButton2.setText("Wählen...");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jLabel3)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jTextField3, javax.swing.GroupLayout.DEFAULT_SIZE, 282, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButton1)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextField3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel3)
                    .addComponent(jButton2)
                    .addComponent(jButton1))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 287, Short.MAX_VALUE)
                .addContainerGap())
        );
        pack();
    }// </editor-fold>//GEN-END:initComponents
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        server = new SocketServer(this);
        jButton1.setEnabled(false); jButton2.setEnabled(false);
    }//GEN-LAST:event_jButton1ActionPerformed
    public void RetryStart(int port){
        if(server != null){ server.stop(); }
        server = new SocketServer(this, port);
    }
    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        fileChooser.showDialog(this, "Auswählen");
        File file = fileChooser.getSelectedFile();
        if(file != null){
            filePath = file.getPath();
            if(this.isWin32()){ filePath = filePath.replace("\\", "/"); }
            jTextField3.setText(filePath);
            jButton1.setEnabled(true);
        }
    }//GEN-LAST:event_jButton2ActionPerformed
    public static void main(String args[]) {
        try{
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch(Exception ex){
            System.out.println("Look & Feel Exception");
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ServerFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JScrollPane jScrollPane1;
    public javax.swing.JTextArea jTextArea1;
    private javax.swing.JTextField jTextField3;
    // End of variables declaration//GEN-END:variables
}
```

*SocketServer.java*

```
package de.steinadler5.socket;
import java.io.*;
import java.net.*;
class ServerThread extends Thread {
    public SocketServer server = null;
    public Socket socket = null;
    public int ID = -1;
    public String username = "";
    public ObjectInputStream streamIn  =  null;
    public ObjectOutputStream streamOut = null;
    public ServerFrame ui;
    public ServerThread(SocketServer _server, Socket _socket){ 
        super();
        server = _server;
        socket = _socket;
        ID     = socket.getPort();
        ui = _server.ui;
    }
    public void send(Message msg){
        try {
            streamOut.writeObject(msg);
            streamOut.flush();
        }
        catch (IOException ex) {
            System.out.println("Exception [SocketClient : send(...)]");
        }
    }
    public int getID(){ 
        return ID;
    }
    @SuppressWarnings("deprecation")
    public void run(){ 
        ui.jTextArea1.append("\nServer Thread " + ID + " running.");
        while (true){ 
            try{ 
                Message msg = (Message) streamIn.readObject();
                server.handle(ID, msg);
            }
            catch(Exception ioe){ 
                System.out.println(ID + " ERROR reading: " + ioe.getMessage());
                server.remove(ID);
                stop();
            }
        }
    }
    public void open() throws IOException { 
        streamOut = new ObjectOutputStream(socket.getOutputStream());
        streamOut.flush();
        streamIn = new ObjectInputStream(socket.getInputStream());
    }
    public void close() throws IOException { 
        if (socket != null)    socket.close();
        if (streamIn != null)  streamIn.close();
        if (streamOut != null) streamOut.close();
    }
}
public class SocketServer implements Runnable {
    public ServerThread clients[];
    public ServerSocket server = null;
    public Thread       thread = null;
    public int clientCount = 0, port = 13000;
    public ServerFrame ui;
    public Database db;
    public SocketServer(ServerFrame frame){
        clients = new ServerThread[50];
        ui = frame;
        db = new Database(ui.filePath);
    try{ 
        server = new ServerSocket(port);
            port = server.getLocalPort();
        ui.jTextArea1.append("Server startet. IP : " + InetAddress.getLocalHost() + ", Port : " + server.getLocalPort());
        start();
        }
    catch(IOException ioe){ 
            ui.jTextArea1.append("Can not bind to port : " + port + "\nRetrying");
            ui.RetryStart(0);
    }
    }
    public SocketServer(ServerFrame frame, int Port){
        clients = new ServerThread[50];
        ui = frame;
        port = Port;
        db = new Database(ui.filePath);
    try{ 
        server = new ServerSocket(port);
            port = server.getLocalPort();
        ui.jTextArea1.append("Server startet. IP : " + InetAddress.getLocalHost() + ", Port : " + server.getLocalPort());
        start();
        }
    catch(IOException ioe){ 
            ui.jTextArea1.append("\nCan not bind to port " + port + ": " + ioe.getMessage());
    }
    }
    public void run(){ 
    while (thread != null){ 
            try{ 
        ui.jTextArea1.append("\nWaiting for a client ...");
            addThread(server.accept());
        }
        catch(Exception ioe){
                ui.jTextArea1.append("\nServer accept error: \n");
                ui.RetryStart(0);
        }
        }
    }
    public void start(){ 
        if (thread == null){ 
            thread = new Thread(this);
        thread.start();
    }
    }
    @SuppressWarnings("deprecation")
    public void stop(){ 
        if (thread != null){ 
            thread.stop();
        thread = null;
    }
    }
    private int findClient(int ID){ 
        for (int i = 0; i < clientCount; i++){
            if (clients[i].getID() == ID){
                    return i;
                }
    }
    return -1;
    }
    public synchronized void handle(int ID, Message msg){ 
    if (msg.content.equals(".bye")){
            Announce("signout", "SERVER", msg.sender);
            remove(ID);
    }
    else{
            if(msg.type.equals("login")){
                if(findUserThread(msg.sender) == null){
                    if(db.checkLogin(msg.sender, msg.content)){
                        clients[findClient(ID)].username = msg.sender;
                        clients[findClient(ID)].send(new Message("login", "SERVER", "TRUE", msg.sender));
                        Announce("newuser", "SERVER", msg.sender);
                        SendUserList(msg.sender);
                    }
                    else{
                        clients[findClient(ID)].send(new Message("login", "SERVER", "FALSE", msg.sender));
                    }
                }
                else{
                    clients[findClient(ID)].send(new Message("login", "SERVER", "FALSE", msg.sender));
                }
            }
            else if(msg.type.equals("message")){
                if(msg.recipient.equals("All")){
                    Announce("message", msg.sender, msg.content);
                }
                else{
                    findUserThread(msg.recipient).send(new Message(msg.type, msg.sender, msg.content, msg.recipient));
                    clients[findClient(ID)].send(new Message(msg.type, msg.sender, msg.content, msg.recipient));
                }
            }
            else if(msg.type.equals("test")){
                clients[findClient(ID)].send(new Message("test", "SERVER", "OK", msg.sender));
            }
            else if(msg.type.equals("signup")){
                if(findUserThread(msg.sender) == null){
                    if(!db.userExists(msg.sender)){
                        db.addUser(msg.sender, msg.content);
                        clients[findClient(ID)].username = msg.sender;
                        clients[findClient(ID)].send(new Message("signup", "SERVER", "TRUE", msg.sender));
                        clients[findClient(ID)].send(new Message("login", "SERVER", "TRUE", msg.sender));
                        Announce("newuser", "SERVER", msg.sender);
                        SendUserList(msg.sender);
                    }
                    else{
                        clients[findClient(ID)].send(new Message("signup", "SERVER", "FALSE", msg.sender));
                    }
                }
                else{
                    clients[findClient(ID)].send(new Message("signup", "SERVER", "FALSE", msg.sender));
                }
            }
            else if(msg.type.equals("upload_req")){
                if(msg.recipient.equals("All")){
                    clients[findClient(ID)].send(new Message("message", "SERVER", "Uploading to 'All' forbidden", msg.sender));
                }
                else{
                    findUserThread(msg.recipient).send(new Message("upload_req", msg.sender, msg.content, msg.recipient));
                }
            }
            else if(msg.type.equals("upload_res")){
                if(!msg.content.equals("NO")){
                    String IP = findUserThread(msg.sender).socket.getInetAddress().getHostAddress();
                    findUserThread(msg.recipient).send(new Message("upload_res", IP, msg.content, msg.recipient));
                }
                else{
                    findUserThread(msg.recipient).send(new Message("upload_res", msg.sender, msg.content, msg.recipient));
                }
            }
    }
    }
    public void Announce(String type, String sender, String content){
        Message msg = new Message(type, sender, content, "All");
        for(int i = 0; i < clientCount; i++){
            clients[i].send(msg);
        }
    }
    public void SendUserList(String toWhom){
        for(int i = 0; i < clientCount; i++){
            findUserThread(toWhom).send(new Message("newuser", "SERVER", clients[i].username, toWhom));
        }
    }
    public ServerThread findUserThread(String usr){
        for(int i = 0; i < clientCount; i++){
            if(clients[i].username.equals(usr)){
                return clients[i];
            }
        }
        return null;
    }
    @SuppressWarnings("deprecation")
    public synchronized void remove(int ID){ 
    int pos = findClient(ID);
        if (pos >= 0){ 
            ServerThread toTerminate = clients[pos];
            ui.jTextArea1.append("\nRemoving client thread " + ID + " at " + pos);
        if (pos < clientCount-1){
                for (int i = pos+1; i < clientCount; i++){
                    clients[i-1] = clients[i];
            }
        }
        clientCount--;
        try{ 
              toTerminate.close();
        }
        catch(IOException ioe){ 
              ui.jTextArea1.append("\nError closing thread: " + ioe);
        }
        toTerminate.stop();
    }
    }
    private void addThread(Socket socket){ 
    if (clientCount < clients.length){ 
            ui.jTextArea1.append("\nClient accepted: " + socket);
        clients[clientCount] = new ServerThread(this, socket);
        try{ 
              clients[clientCount].open();
            clients[clientCount].start(); 
            clientCount++;
        }
        catch(IOException ioe){ 
              ui.jTextArea1.append("\nError opening thread: " + ioe);
        }
    }
    else{
            ui.jTextArea1.append("\nClient refused: maximum " + clients.length + " reached.");
    }
    }
}
```

*Message.java*

```
package de.steinadler5.socket;
import java.io.Serializable;
public class Message implements Serializable{
    private static final long serialVersionUID = 1L;
    public String type, sender, content, recipient;
    public Message(String type, String sender, String content, String recipient){
        this.type = type; this.sender = sender; this.content = content; this.recipient = recipient;
    }
    @Override
    public String toString(){
        return "{type='"+type+"', sender='"+sender+"', content='"+content+"', recipient='"+recipient+"'}";
    }
}
```

*Database.java*

```
package de.steinadler5.socket;
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
public class Database {
    public String filePath;
    public Database(String filePath){
        this.filePath = filePath;
    }
    public boolean userExists(String username){
        try{
            File fXmlFile = new File(filePath);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(fXmlFile);
            doc.getDocumentElement().normalize();
            NodeList nList = doc.getElementsByTagName("user");
            for (int temp = 0; temp < nList.getLength(); temp++) {
                Node nNode = nList.item(temp);
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element eElement = (Element) nNode;
                    if(getTagValue("username", eElement).equals(username)){
                        return true;
                    }
                }
            }
            return false;
        }
        catch(Exception ex){
            System.out.println("Database exception : userExists()");
            return false;
        }
    }
    public boolean checkLogin(String username, String password){
        if(!userExists(username)){ return false; }
        try{
            File fXmlFile = new File(filePath);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(fXmlFile);
            doc.getDocumentElement().normalize();
            NodeList nList = doc.getElementsByTagName("user");
            for (int temp = 0; temp < nList.getLength(); temp++) {
                Node nNode = nList.item(temp);
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element eElement = (Element) nNode;
                    if(getTagValue("username", eElement).equals(username) && getTagValue("password", eElement).equals(password)){
                        return true;
                    }
                }
            }
            System.out.println("Hippie");
            return false;
        }
        catch(Exception ex){
            System.out.println("Database exception : userExists()");
            return false;
        }
    }
    public void addUser(String username, String password){
        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(filePath);
            Node data = doc.getFirstChild();
            Element newuser = doc.createElement("user");
            Element newusername = doc.createElement("username"); newusername.setTextContent(username);
            Element newpassword = doc.createElement("password"); newpassword.setTextContent(password);
            newuser.appendChild(newusername); newuser.appendChild(newpassword); data.appendChild(newuser);
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(new File(filePath));
            transformer.transform(source, result);
       }
           catch(Exception ex){
        System.out.println("Exceptionmodify xml");
       }
    }
    public static String getTagValue(String sTag, Element eElement) {
    NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
        Node nValue = (Node) nlList.item(0);
    return nValue.getNodeValue();
  }
}
```

Wäre richig nice wenn mir einer helfen kann.
MFG Luca.


----------



## MTJ004 (18. Sep 2016)

Würde gerne helfen bin aber selber nicht gut genug


----------



## thomasbomme (19. Sep 2016)

ich würde an deiner Stelle nicht diesen Chat umschreiben sondern einen neuen erstellen, und manche Codezeilen von diesem übernehmen... geht wsl. schneller


----------



## NeCIAx (19. Sep 2016)

Hallo wie *thomasbomme* schon sagte es geht schneller das Ding direkt von neu auf Konsolen Basis zu bauen, aber das ist auch nicht so schwer zu realisieren. 

Ich denke mal das du über die Konsole dann auch befehle verwenden können willst.
Das habe ich z.B. mit einem normalen Scanner mal gebaut.


----------



## XyMorgan (20. Sep 2016)

Der Post war ja schon was älter, ob da noch bedarf ist? Ansonsten, wenn man reinschaut in den Code erkennt man, dass es ein reines Server-Modul ist, dass in eine GUI gepackt wurde. Lässt sich so auf einem VServer (i.d.R. ohne Grafiksupport) nicht starten. Die Nachrichten kommen nachher vom Client der sich connected. Umbau ist eher simpel. Hatte es mal fix gemacht und gesehen, dass der Post etwas älter ist.

Im Grunde ServerFrame raus, MainApp-Klasse erstellen (oder ServerSocket zur App umbauen). Entweder pfad für die Config/Logindatei über Parameter oder fix im Code. In der Klasse SocketServer die Infoausgaben zur GUI raus und ggf. in die Console/Log schreiben. Fertig.

Was hier außer dem Socket nutzbar ist, ist das Login der Clients über Anmeldung und Persistenz in der Datei.


----------



## JuKu (18. Okt 2016)

Der Client & Server Code sollte immer getrennt sein (abgesehen von Gemeinsamkeiten), sodass der Server gar keine GUI hat.
Du solltest Server immer in der Console starten.

Nur als Tipps, falls du das ganze mal ausbauen solltest:
Es ist keine gute Idee, für jede Verbindung einen eigenen Thread zu erstellen, auch wenn dies in vielen Anfänger Tutorials so gehandhabt wird.
Stattdessen solltest du Thread Pools oder Executor Services nutzen.

Als Network Library kann ich dir übrigens http://netty.io empfehlen, oder du nutzt socket.io, ebenfalls sehr nice.


----------



## JuKu (31. Okt 2016)

Ich habe übrigens mittlerweile ein Tutorial geschrieben, wie man einen Chat Server implementieren könnte:
http://jukusoft.com/index.php/2016/10/26/tutorial-chat-server-java/
http://jukusoft.com/index.php/2016/10/26/tutorial-chat-server-java/
Vllt. hilft es dir ja ein wenig weiter.


----------



## neoexpert (31. Okt 2016)

Willst du meinen nodejs chat haben? Server läuft auf allen bekannten Systemen (Voraussetzung nodejs) und als Clients kannst du meine Android APP (NeoChat) oder auch im Browser haben: Beispiel:
www.lean-production-shop.de
Unten rechts ist ein div, dort kann man chatten.
PS: man kann mit der APP auch Dateien über den selben Port versenden.


----------



## neoexpert (31. Okt 2016)

O tschuldigung, hab nicht gesehen, dass der post von Juli ist.


----------

