Semantisches Problem HashMap/Netzwerk

MR_UNIX

Bekanntes Mitglied
Hallo Leute,

wie man im Titel schon erkennen kann, habe ich ein semantisches Problem in meinem Code.
Ich habe zwar schon versucht, per Debugging dahinter zu kommen, konnte es aber leider selber nicht lösen, weshalb ich mich nun an euch wende.

Es geht um ein kleine Chat-Programm, was ich momentan entwickle. Später wird es ein Instant-Messenger, welcher alle Nachrichten verschlüsselt überträgt, momentan ist es aber "nur" ein Global-Chat, in dem alle gesendeten Nachrichten bei jedem Client landen. Natürlich möchte ich, dass die anderen sehen, wer welche Nachricht versendet hat. Allerdings wird immer "null" als Name angezeigt.
Und damit sind wir auch schon mitten im Problem. Ich kann mir nicht erklären, warum er nicht den richtigen Namen aus der HashMap zieht, sondern "null".

Um diesen Code geht es:

TextSenderServer.java
Java:
package de.mrpixeldream.beta.textsender.server;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Random;

import de.mrpixeldream.beta.textsender.server.handler.ClientHandler;

public class TextSenderServer
{
	static int port;
	
	static FileWriter logger;
	
	static HashMap<String, Socket> clients;
	static HashMap<String, String> names;
	static public HashMap<InetAddress, String> ips;
	static HashMap<String, String> ids;
	
	static Random idGenerator;
	
	static ServerSocket server;
	
	public static void main(String[] args)
	{
		File logfile = new File("logfile.log"); 
		
		System.out.println("Welcome to ChatBase chat server! The small chat solution.");
		System.out.println("Setting up variables...");
		
		clients = new HashMap<String, Socket>();
		names = new HashMap<String, String>();
		ips = new HashMap<InetAddress, String>();
		ids = new HashMap<String, String>();
		
		System.out.println("Done. Creating logger...");
		
		try
		{
			logger = new FileWriter(logfile, true);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		System.out.println("Logger created, events are logged now.");
		
		if (args.length == 1)
		{
			port = Integer.parseInt(args[0]);
			try
			{
				log("Set port to " + port);
				System.out.println("Server port: " + port);
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		else
		{
			port = 22558;
			try
			{
				log("Set port to " + port);
				System.out.println("Server port: " + port);
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		
		log("Creating socket...");
		System.out.println("Creating socket...");
		
		try
		{
			server = new ServerSocket(port);
			System.out.println("Server now listening for new connections...");
			
			while (true)
			{
				Socket client;
				client = server.accept();
				System.out.println("Connected from " + client.getInetAddress());
				new ClientHandler(client).start();
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
			log("Got error while creating socket:");
			log(e.getMessage());
		}
		
		try
		{
			System.out.println("Closing logger...");
			logger.flush();
			logger.close();
			System.out.println("Closed. Server shutting down!");
		}
		catch (Exception ex)
		{
			System.err.println("Logger not closed properly.");
		}
	}
	
	private static String datePrefix()
	{
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd | HH:mm:ss");
		Date currentTime = new Date(System.currentTimeMillis());
		return "[" + format.format(currentTime) + "]: ";
	}
	
	public static void log(String msg)
	{
		try
		{
			logger.write(datePrefix() + msg + "\n\n");
			logger.flush();
		}
		catch (Exception ex)
		{
			System.err.println("Can't write to log.");
		}
		System.err.println(msg);
	}
	
	public static String doLogin(Socket client, String name)
	{
		String id;
		if (!clients.containsValue(client.getInetAddress()) && !names.containsValue(name) && !ips.containsKey(client.getInetAddress()))
		{
			do
			{
				id = makeId();
			} while (clients.containsKey(id));
			
			clients.put(id, client);
			names.put(id, name);
			ips.put(client.getInetAddress(), id);
			ids.put(name, id);
			System.out.println("Logged in from " + client.getInetAddress() + " with ID " + id);
			return "Successfully logged in! Got ID: " + id;
		}
		else if (names.containsValue(name))
		{
			return "This user is already online!";
		}
		else if (ips.containsKey(client.getInetAddress()))
		{
			return "This IP is already connected!";
		}
		else
		{
			return "Login failed. Unkown error!";
		}
	}
	
	public static void doLogout(InetAddress addr)
	{
		String clientID = ips.get(addr);
		sendMessage(clientID, "Logging you out...");
		Socket sock = clients.get(clientID);
		clients.remove(clientID);
		try
		{
			sock.close();
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		names.remove(clientID);
		ips.remove(addr);
	}
	
	private static String makeId()
	{
		idGenerator = new Random(System.currentTimeMillis() | 5);
		String id = String.valueOf(idGenerator.nextInt(9998) + 1);
		while (id.length() < 4)
		{
			String tmp = "0";
			id = tmp + id;
		}
		
		return id;
	}
	
	public static Object[] listClients()
	{
		return names.keySet().toArray();
	}
	
	public static String clientNameByID(String id)
	{
		return names.get(id);
	}
	
	public static String idByName(String name)
	{
		if (ids.containsKey(name))
		{
			return ids.get(name);
		}
		else
		{
			return "No client with this ID found!";
		}
	}
	
	public static void sendMessage(String id, String message)
	{
		try
		{
			PrintWriter writer = new PrintWriter(clients.get(id).getOutputStream());
			writer.println(message);
			writer.flush();
			writer = null;
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public static void broadcastMessage(String message)
	{	
		try
		{
			for (String client : clients.keySet())
			{
				PrintWriter writer = new PrintWriter(clients.get(client).getOutputStream());
				writer.println(message);
				writer.flush();
				writer = null;
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

ClientHandler.java
Java:
package de.mrpixeldream.beta.textsender.server.handler;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

import de.mrpixeldream.beta.textsender.server.TextSenderServer;

public class ClientHandler extends Thread
{
	Socket client;
	String id;
	Scanner input;
	PrintWriter output;
	
	public ClientHandler(Socket client)
	{
		this.client = client;
		
		this.id = TextSenderServer.ips.get(client.getInetAddress());
		
		try
		{
			this.input = new Scanner(client.getInputStream());
			this.output = new PrintWriter(client.getOutputStream());
			
			this.output.println("ACK");
			this.output.flush();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	@Override
	public void run()
	{
		String msg = "";
		
		do
		{
			msg = "";
			
			try
			{
				msg = this.input.nextLine();
				msg.toUpperCase();
			}
			catch (Exception e)
			{
				TextSenderServer.log("Failed to read line from client! Logging out...");
				msg = "LOGOUT";
			}
			
			if (msg.toUpperCase().startsWith("LOGIN"))
			{
				this.output.println(TextSenderServer.doLogin(client, msg.split(" ")[1]));
				this.output.flush();
			}
			if (msg.toUpperCase().startsWith("SHOW"))
			{
				for (Object now : TextSenderServer.listClients())
				{
					this.output.println(now);
				}
				this.output.flush();
			}
			if (msg.toUpperCase().startsWith("SEND"))
			{
				String id = msg.split(" ")[1];
				String send = "";
				
				for (int i = 2; i < msg.split(" ").length; i++)
				{
					send += msg.split(" ")[i] + " ";
				}
				
				try
				{
					Integer.parseInt(id);
					TextSenderServer.sendMessage(id, send);
				}
				catch (NumberFormatException e)
				{
					TextSenderServer.sendMessage(TextSenderServer.idByName(id), send);
				}
			}
			if (msg.toUpperCase().startsWith("BROADCAST"))
			{
				String send = TextSenderServer.clientNameByID(id) + ": ";
				
				for (int i = 1; i < msg.split(" ").length; i++)
				{
					send += msg.split(" ")[i] + " ";
				}
				
				TextSenderServer.broadcastMessage(send);
			}
		} while (!msg.equalsIgnoreCase("LOGOUT"));
		
		TextSenderServer.doLogout(client.getInetAddress());
	}
}

Habe jetzt mal den kompletten Server-Code gepostet, da da (noch) keine großen Geheimnisse drinstecken. Ich hoffe, es ist nicht all zu unübersichtlich.
Sicher sind da noch einige unschöne Sachen wie viel zu viele Statics drin, aber darum soll's jetzt erst einmal nicht gehen, sondern um den oben beschriebenen Semantik-Fehler.
Falls ihr den Server nicht auf dem eigenen Rechner laufen lassen wollt, passt einfach im Client bei der Verbindung das "localhost" auf "dream-code.net" an, dort läuft der Server immer in der aktuellsten Version.

Vielen Dank schon einmal!
 
Was mir eben mal auffällt:
Java:
                this.output.println(TextSenderServer.doLogin(client, msg.split(" ")[1]))

Wenn die Message mehr als ein Leerzeichen hat, dann kommst du da in Schwierigkeiten. Ich würde auch vermuten, dass da der Fehler liegt. Du solltest vielleicht eher ein replaceFirst machen machen und dann noch mal trim.
 
Hi,

danke erst einmal für deine Antwort. Daran kann es aber nicht liegen, da im Client der Login über folgende Zeile ausgeführt wird:
Code:
String srvMessage = "LOGIN " + this.txtName.getText().trim();

Daraus folgt, dass auf jeden Fall nur ein Leerzeichen im Login Kommando enthalten ist.
 
Vielleicht sollte ich noch anmerken, dass das Problem im untersten If-Block (BROADCAST) der ClientHandler.java auftritt. Offenbar findet clientNameById() anhand der ID keinen Client, obwohl aber einer eingeloggt ist. Nur wieso? :/

// EDIT: Im Anhang jetzt einmal die Client.jar und Client.src.zip, damit ihr euch vom (unfertigen) Client ein Bild machen könnt. Wie oben erwähnt, läuft auf dream-code.net:22558 ein Server, falls ihr den nicht auf dem eigenen Rechner laufen lassen wollt. Einfach im Login Fenster einen beliebigen Namen eingeben, und dann eine Nachricht versenden, dann seht ihr, was ich meine.
 

Anhänge

Zuletzt bearbeitet:
Fixed it! 😀 Ich habe das Abrufen des Clientnamens bzw. der ID im Konstruktor der ClientHandler Klasse ausgeführt, dort ist der Client aber eben noch nicht eingeloggt. Habe das ganze an's Ende vom LOGIN Block verschoben, nun geht es *yay*!

Danke trotzdem!
 

Zurück
Oben