La explicación del Programa
He creado un servidor de sala de chat utilizando Java que consiste en 3 clases, una clase de servidor, una clase de usuario y una clase sala de chat. También he creado una clase de cliente para interactuar con el servidor. El servidor crea un objeto de usuario cada vez que un cliente se conecta al servidor. Cada objeto de usuario comprueba los salas de chat el usuario está en y se ejecuta un hilo que escuchas para la entrada del usuario. Un objeto de servidor recorre cada sala de chat para ver si se ha utilizado en la última semana.
El problema
Me pregunto cómo realmente hacer una conexión con un servidor con el objeto de cliente. Actualmente puedo abrir dos instancias de eclipse. Tengo mi programa de servidor en uno, y mi programa cliente en el otro, pero recibo nada en la consola de cualquiera, lo que debería suceder porque el servidor debe enviar información al cliente, que el cliente se mostrará en la consola. La persona en el cliente final podría entonces dar entrada que el cliente iba a tomar y enviar al servidor.
Me pregunto por qué no está pasando nada en este momento, y qué mejoras puedo hacer.
principal archivos
Server.java
/*
* Creates a server that can host up to 10 clients who can join chat rooms, post messages in chatrooms, and view posts made by other clients within the same chat room
*/
public class Server implements Runnable{
protected ArrayList<User> userList; //A list of users, where each user is a client connected to the server
protected LinkedList<Chatroom> chatRooms; //A list of chatrooms where each client can post messages in, where messages can be seen by all clients in the chatroom
private ServerSocket serverSocket; //The socket for the server
/*
* Constructor for the server class. Initializes the server attributes,
*/
public Server() {
this.userList = new ArrayList<User>(10);
this.chatRooms = new LinkedList<Chatroom>();
try {
this.serverSocket = new ServerSocket(5000);
}catch (IOException e) {
e.printStackTrace();
}
}
/*
* Creates a new user when a client connects to the server, and starts a user thread
*/
public void createUser() {
try {
Socket userSocket = serverSocket.accept();
Thread user = new Thread(new User(userSocket, this));
user.start();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* Creates a chatroom for clients to interact in
* @param roomName: The name of the chat room to be created
*/
protected Chatroom createChatRoom(String roomName) {
Chatroom room = new Chatroom(roomName);
return room;
}
/*
* Receives messages from clients and performs actions based on the requests of the client
* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
long currentTime;
while(true) {
try {
currentTime = System.currentTimeMillis() / 1000;
//Loop through each chatroom and check if the chatroom has been used(joined or had a message sent to it) and remove that chatroom if it hasn't been used in a week
for (int i = 0; i < chatRooms.size(); i++) {
if (currentTime - 604800 >= chatRooms.get(i).dateLastUsed) {
chatRooms.remove(i);
//Also remove the chatroom from clients lists of chatrooms
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
Server server = new Server ();
server.run();
}
}
Client.java
public class Client extends Thread{
private String ip = "127.0.0.1";
private int port = 5000 ;
private Socket socket;
private DataInputStream iStream;
private DataOutputStream oStream;
private String input;
public Client() {
try {
this.socket = new Socket(ip, port);
this.iStream = new DataInputStream(socket.getInputStream());
this.oStream = new DataOutputStream(socket.getOutputStream());
}catch (Exception e) {
e.printStackTrace();
}
}
/*
* Sends a message to the user
* @param message: The message to be sent to the user
*/
protected void send (String message) {
try {
oStream.writeUTF(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* Closes the connection to the client
*/
protected void close () {
try {
iStream.close();
oStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* Runs a thread for the client to constantly receive the clients input(non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
try {
Scanner reader = new Scanner(System.in);
input = iStream.readUTF();
String userInput;//Check if there is input from the user
while (input != null) {
input = iStream.readUTF();
System.out.println(input);
userInput = reader.next();
oStream.writeUTF(userInput);
}
reader.close();
}catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
Client client = new Client();
client.run();
}
}
Objetos utilizados por Server.java
User.java
//Each user represents a client that has connected to the server
public class User implements Runnable{
private DataInputStream inputStream;
private DataOutputStream outputStream;
private Socket socket;
private String name;
protected LinkedList<Chatroom> chatRooms;
private String input;
private Server server;
/*
* User Constructor, create a user for each client connecting to the server
* @socket The socket that the user will be communicated through
* The client is prompted to create a name for themself, they are they prompted to do an action.
*/
public User(Socket socket, Server server) {
this.socket = socket;
this.server = server;
try {
inputStream = new DataInputStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeUTF("Enter a name");
this.name = inputStream.readUTF();
String message = "Create a chatroom: create \nList Chat Rooms: list \n Join Chat Room: join \n Leave Chat Room: Leave";
send(message);
} catch (IOException e) {
}
}
/*
* Returns the current amount of chatrooms this user is in
*/
protected int chatRoomLength () {
return this.chatRooms.size();
}
/*
* Gets the most recent input from the user
*/
protected String getInput() {
return input;
}
/*
* Puts a user/client in a chatroom
* @param cRoom: The chatroom that the user will join
*/
protected void joinRoom (Chatroom cRoom) {
chatRooms.add(cRoom);
}
/*
* Removes a user/client from a chatroom
*/
protected void leaveRoom (Chatroom c) {
chatRooms.removeFirstOccurrence(c);
}
/*
* Sends a message to the user
* @param message: The message to be sent to the user
*/
protected void send (String message) {
try {
outputStream.writeUTF(message);
} catch (IOException e) {
}
}
/*
* Closes the connection to the client
*/
protected void close () {
try {
inputStream.close();
outputStream.close();
socket.close();
} catch (IOException e) {}
}
/*
* Runs a thread for the client to constantly receive the clients input(non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
try {
input = inputStream.readUTF(); //Check if there is input from the user
//if the user has disconnected from the server, remove them from the list
if (input == null) {
this.close();
this.server.userList.remove(this);
}else if (input.equals("create")){ //create a chat room
this.send("Name the Chatroom");
input = this.getInput();
Chatroom c = this.server.createChatRoom(input);
this.joinRoom(c);
}else if (input.equals("list")) { //List the current chatrooms
String rooms = "";
for (int j = 0; j< server.chatRooms.size(); j++) {
rooms = rooms + server.chatRooms.get(j).getName() + "\n";
}
this.send(rooms);
}else if (input.equals("join")) { //Join the user to a chat room
int end = chatRooms.size();
if (end == 0) {
this.send("There's currently no chat rooms");
}else {
this.send("Which room would you like to join");
input = this.getInput();
for (int k = 0; k < end; k++) {
if (chatRooms.get(k).getName().equals(input)) {
Chatroom joinRoom = chatRooms.get(k);
this.joinRoom(joinRoom);
String message = "Chatroom " + input + " messages. \n";
//Print the current messages in the chatroom to the user
for (int j = 0; j < joinRoom.messages.size(); j++ ) {
message = message + joinRoom.messages.get(j) + "\n";
}
this.send(message);
} else if (k == end - 1) {
this.send("There's no chat rooms by that name");
}
}
}
}else if (input.equals("leave")) { //Remove the user from a chatroom
int end = this.chatRoomLength(); //if the chatroom list of the user is empty
if (end == 0) {
this.send("You are not in any Chat Rooms");
}else {
this.send("Which room would you like to leave");
input = this.getInput();
for (int m = 0; m < end; m++) { //find the chatroom by the same name
if (this.chatRooms.get(m).getName().equals(input)) {
this.chatRooms.remove(m);
this.send("Great! You've been removed from" + input);
} else if (m == end - 1) {
this.send("You're not in a chatroom named" + input);
}
}
}
}else { //All other input is interpreted as a message to be posted in the chatrooms that the user is in
int end = this.chatRoomLength();
if (end == 0) {
this.send("You can't write to any chat rooms because you are not in any");
}
for (int m = 0; m < end; m++) { //Add the users message to ALL the chatrooms the user is in
Chatroom c = this.chatRooms.get(m);
c.addMessage(input);
//Send this added message to all the users in this chatroom
for (int n = 0; n < c.users.size(); n++) {
User u = c.users.get(n);
u.send("Chatroom" + c.getName() + ":" + input);
}
}
}
}catch (IOException e) {
}
}
}
Chatroom.java
public class Chatroom {
private String name; //Name of the chatroom
protected LinkedList<String> messages; //List of text messages that have been sent by users to the chatroom and are displayed in the chatroom
protected long dateLastUsed; //The last time the chatroom was joined or had a message sent to it
protected LinkedList<User> users; //The clients/users that are currently in the chatroom
/*
* Chatroom constructor
* @param name The name of the chatroom, as determined by the user creating it
*/
public Chatroom(String name) {
dateLastUsed = System.currentTimeMillis() / 1000; //Sent the time that the chatroom was used last to the current UNIX Epoch time
messages = new LinkedList<String>();
this.name = name;
}
/*
* Adds a message into the chatroom
* @param message The message to be added to the chatroom
*/
protected void addMessage(String message) {
messages.add(message);
dateLastUsed = System.currentTimeMillis() / 1000;
}
/*
* Returns the name of the chatroom
* @return String equal to the name of the chatroom
*/
protected String getName() {
return this.name;
}
}
En primer lugar, no hay una llamada a createUser()
la que tiene el código para aceptar la conexión de socket.
El siguiente es el código de run()
la función,
try {
Scanner reader = new Scanner(System.in);
input = iStream.readUTF();
String userInput;//Check if there is input from the user
while (input != null) {
input = iStream.readUTF();
System.out.println(input);
userInput = reader.next();
oStream.writeUTF(userInput);
}
Una vez que el enchufe se acepta los grabados de servidor Enter a name
que se almacenan de entrada, dentro del bucle, mientras que hay otra readUTF()
llamada.
El problema con la readUTF()
llamada es que está bloqueando, es decir. si no hay una writeUTF()
llamada desde el servidor espera a los datos.
He resuelto el problema por el siguiente fragmento,
try {
Scanner reader = new Scanner(System.in);
String userInput;//Check if there is input from the user
do {
input = iStream.readUTF();
System.out.println(input);
userInput = reader.next();
oStream.writeUTF(userInput);
} while (input != null);
reader.close();
}
Incluso esta no es la solución óptima, ya que necesitaría servidor de escribir algo en la corriente cada vez.
Otra solución sería la de leer y escribir utilizando diferentes hilos de esa manera que sería capaz de crear un full-duplex como el chat, a diferencia de este medio dúplex.
Luego hubo algunos NPE debido a ninguna inicialización de chatRooms
LinkedList,
Además de algunos errores lógicos gusta, no añadiendo salas de chat a su lista.
Codigo erroneo:
protected Chatroom createChatRoom(String roomName) {
Chatroom room = new Chatroom(roomName);
return room;
}
Corregido Código:
protected Chatroom createChatRoom(String roomName) {
Chatroom room = new Chatroom(roomName);
this.chatRooms.add(room);
return room;
}
La mejor manera de resolver todos los errores sería Github y algunos colaboradores: p