3

I am trying to access data from my list but it always end up with null or nothing in it. I run my Class Server That have public static ArrayList<String> clientUsernameList = new ArrayList<>(); In the code. If my server accept a socket this code below should occur.

package multi.threaded_server_application;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.Clock;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import jdk.nashorn.internal.codegen.CompilerConstants;

/**
*
* @author Seeya
*/
public class Server {

public static ArrayList<String> clientUsernameList = new ArrayList<>();

/**
 * @param args the command line arguments
 * @throws java.io.IOException
 */
public static void main(String[] args) throws IOException {

    int port = 8900;    //Port number the ServerSocket is going to use
    ServerSocket myServerSocket = null;  //Serversocket for sockets to connect
    Socket clientSocket = null;    //Listerner for accepted clients
    ClientThread[] clientsConnected = new ClientThread[20]; //Max clients in this server
    DataInputStream IN = null;

    try {
        myServerSocket = new ServerSocket(port);
        System.out.println("Server waiting for clients on port:" + port);
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }

    while (true) {            
        try {   //Freezes while-loop untill a socket have been accepted or if some failure occur
            clientSocket = myServerSocket.accept();
            IN = new DataInputStream(clientSocket.getInputStream());
            String userName = IN.readUTF();
            Server.clientUsernameList.add(userName);

            System.out.println("Client have connected from:" + clientSocket.getLocalAddress().getHostName());
            System.out.println("Username:" + userName);
            System.out.println(Server.clientUsernameList);

        } catch (Exception e) {
            //Print out exception
            System.out.println(e);
        }
        //For-loop that counts every element in Array-clientsConnected
        for (int i = 0; i < clientsConnected.length; i++) {
            //If-statement checks if current element is null 
            if(clientsConnected[i] == null){
                //If current element in the Array is null then create a new object from ClientThread class
                //With a socket and the object of itself as parameter.
                (clientsConnected[i] = new ClientThread(clientSocket, clientsConnected)).start();

                //Must have a break otherwise it will create 20 objects (Exit for-loop)
                break;
            }   //Exit if-statement
        }   //Exit for-loop
    }   //Exit while-loop

}

} I recieve the username from my Class Client when it is running. I print it out to see if I added a username to the list. Now when I try to access the data from my Class Client I recieve nothing/null.

package Server_application;

import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Scanner;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author Seeya
*/
public class Client extends Thread {

ClientGUI GUI = null;
DataInputStream IN = null;
DataOutputStream OUT = null;
Socket SOCKET = null;
String Message = null; 
String userName = null;
String ipAdress = "localhost";
int port = 8900;

public Client(ClientGUI gui,String username) {
    this.userName = username;
    this.GUI = gui;
}



@Override
public void run() {
    try {
            //Handle Input/Output from client
            SOCKET = new Socket(ipAdress, port);
            IN = new DataInputStream(SOCKET.getInputStream());
            OUT = new DataOutputStream(SOCKET.getOutputStream());

            //Sends username to server!
            OUT.writeUTF(userName);                

            System.out.println(Server.clientUsernameList);
            GUI.addToList(Server.clientUsernameList.toString());
            while (true) {
                CheckForMessages(IN);
            }

    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }

 }
//-----------------------------------------------------------------
//Method for sending Messages!
public void write(String s) throws IOException{
    //Writes message to server so it can send it to other clients.
    //Also sends to clients self GUI
    String A = s;
    OUT.writeUTF(A);
    GUI.writeGUI("You said: " + A);
}
//------------------------------------------------------------------
//Method for listening on messages
private void CheckForMessages(DataInputStream in) throws IOException {
    try {
        String IncomingMessage = in.readUTF();        
        System.out.println(IncomingMessage);
        GUI.writeGUI(IncomingMessage);
    } catch (Exception e) {
        System.err.println(e);
    }
}
}

All that is printed out is [] from my Class Client. Is there something wrong with how I try to access my static variable?

EDIT! This is the code I use to send/recieve message to all clients in server.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package multi.threaded_server_application;

import com.sun.security.ntlm.Client;
import java.awt.List;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Clock;
import java.util.ArrayList;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListModel;

/**
 *
 * @author Seeya
 */

//THIS CLASS TAKES CARE OF HANDLING MESSAGES TO OTHER CLIENTS!
//-------------------------------------------------------
public class ClientThread extends Thread {

private ClientThread[] clientsConnected;
private Socket SOCKET = null;
private DataInputStream IN = null;
private DataOutputStream OUT = null;
private String userName = null;
//-------------------------------------------------------    
//Constructor
public ClientThread(Socket socket, ClientThread[] clientThread) {
    this.SOCKET = socket;
    this.clientsConnected = clientThread;
}


//This starts as soon as the constructor is done/been created.
@Override
public void run() {
    try {
        //Handleing the messages
        IN = new DataInputStream(SOCKET.getInputStream());
        OUT = new DataOutputStream(SOCKET.getOutputStream());          
        String message = null;

        while (true) {             
            //This will be read second from the socket DataOutPutStream
            //We will use this string to send a message to every client that is online
            message = IN.readUTF();
            //For-loop to check how many people are actually online
            //for (ClientThread k : clientsConnected) = For each client in clientsConnected ends up in variable k
            for (int i = 0; i < clientsConnected.length; i++) {
                    //don't send message to yourself
                if (clientsConnected[i]!= null && clientsConnected[i].userName != this.userName){ 
                    // loops through all the list and calls the objects sendMessage method.
                    clientsConnected[i].sendMessage(message, userName); 
                }
            }
        }

    } catch (IOException ex) {
        Logger.getLogger(ClientThread.class.getName()).log(Level.SEVERE, null, ex);
    }


}

private void sendMessage(String message, String userName) {

    try {            
        Date date = new Date();
        DateFormat format = new SimpleDateFormat("HH:mm:ss");
        OUT.writeUTF(format.format(date) + " " + userName + " says: " + message);
        OUT.flush();

    } catch (IOException ex) {
        Logger.getLogger(ClientThread.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("Something failed to send message");
    }
}   
}
Bojje
  • 419
  • 7
  • 24
  • So is your class named `Server` or `MultiThreaded_Server_Application`? From what you've shown you're writing to the list in one class and reading from the list in another. – azurefrog Feb 20 '15 at 21:16
  • Oh Sorry. It was called MultiThreaded_Server_Application but I renamed it cause that was a really bad name for a server.. – Bojje Feb 20 '15 at 21:17
  • 2
    You don't provide enough information in your question. Please post *minimal working example* of the code in a way that we'll be able to repro. – Nir Alfasi Feb 20 '15 at 21:18
  • There. These are my two classes that are using the list. Hopefully this helps. – Bojje Feb 20 '15 at 21:31
  • I thought it was fine before... – IByrd Feb 20 '15 at 21:32
  • You are not using that static clientUsernameList anywhere. Only declaring it. At least in that code you gave us. – Teemu Feb 20 '15 at 21:39
  • Where are you synchronizing on the list? Why not use a thread-safe queue from `java.util.concurrent`? If you don't synchronize on a shared mutable object, there's no guarantee that other threads will see changes to it, and no guarantee that it won't be observed in an inconsistent state. – Mike Samuel Feb 20 '15 at 21:40
  • What are you all talking about? In his first statement he said he has `public static ArrayList clientUsernameList = new ArrayList<>();` in class `Server` Which he has initialized in his server. Then from client side application he makes a direct call from `Server.clientUsernameList ` you can't do that... Also if you notice both classes are in the same package. Meaning he is straight calling it from Server expecting the client to just fill in the blanks. Stop trying to confuse him with advanced thread stuff. – IByrd Feb 20 '15 at 22:08
  • Oh so I should have the server send the List to the Client class ? cause I have a third class that handles the messages between all the clients and server. – Bojje Feb 20 '15 at 22:10
  • Yes my answer is the way to go. Trust me. :) I'll edit it a little to match your code. – IByrd Feb 20 '15 at 22:11
  • Want me to edit in the class that handles the messages? – Bojje Feb 20 '15 at 22:17
  • Well wherever you are actually sending the String to the client is where you need to send the client user names. I assume it's in ClientThread or some Connection class? In there you'll need that clientUsernameList to put that for loop in and create the string list as a comma separated value. – IByrd Feb 20 '15 at 22:26
  • I edit the code and tossed in my third class. If you want to look at it :) – Bojje Feb 20 '15 at 22:53
  • Take a look at my answer. I am heading home for the day. I will leave you with one more thing. The server-client is a relationship where neither of them know what's going on until one of them gets sent a String/Object. Then from there server can look at what client said and logically add to it or not. Such as sending to other clients or not. When a client gets a message it only ever gets it from Server's point of view after it was warped by stuff the server did to it or not. – IByrd Feb 20 '15 at 23:30
  • I will look at this first thing in the morning. Going to bed since it's really late here. Thanks for the help so far :) – Bojje Feb 20 '15 at 23:41

1 Answers1

1

If you want the clients user names from the server String get that static off of it and you will need to send the clients the user names over the sockets you created using a loop and the clients will need code to read in a username list.


I don't know if this is going to magic bullet your program into doing what you want but this will be more than enough code to get the concept I think.

In your server class

while (true) {            
    try {   //Freezes while-loop until a socket have been accepted or if some failure occur
        clientSocket = myServerSocket.accept();
        IN = new DataInputStream(clientSocket.getInputStream());
        String userName = IN.readUTF();
        OnConnect(userName); // Where to call the below method.

        System.out.println("Client have connected from:" + clientSocket.getLocalAddress().getHostName());
        System.out.println("Username:" + userName);
        System.out.println(Server.clientUsernameList);

    } catch (Exception e) {
        //Print out exception
        System.out.println(e);
    }


//.... More of your code.
String userNamesCSVs = ""

private void OnConnect(String theNewConnectionName){
    //For-Each loop says for every ClientThread object in clientsConnected do this block of code
    for(ClientThread client : clientsConnected){
        //Construct a long string with comma's in it.
        userNamesCSVs = userNamesCSVs + client.userName + ",";
    }
    //Don't forget to count the new name! This was added so you didn't have to do 
    //tricky stuff in the above for loop with the trailing comma. Also the server
    //doesn't have your user name yet.
    userNamesCSVs = userNamesCSVs + theNewConnectionName;
    //New for loop to start sending a mass message. Same as before.
    for(ClientThread client : clientsConnected){
        client.sendMessage(userNamesCSVs, userName);
    }
    //Remember take that static off clientUsernameList. Look up static it's not what you want here.

clientUsernameList.add(userName);
}

In your client class where you are taking in messages from the server.

String[] userNameArray = new String[20]; //Max users and what not.
//Same method you are using named check for messages. It's needed to get the data from the server.
private void getUserNames(DataInputStream in) throws IOException{
    try {
        String userNames = in.readUTF();        
        System.out.println(IncomingMessage);
        userNameArray = userNames.split(",")
    } catch (Exception e) {
        System.err.println(e);
    }
    for(String user : userNames){
        GUI.writeGuid("User connected: " + user);
    }
}

Side Note:

Another thing to look up is the 'serializable' and byte streams and other cool stuff like that. It's pretty easy to do once you master sending Strings back and forth through clients and server. Basically you can send whole objects instead of just Strings as long as it's serializable.

Community
  • 1
  • 1
IByrd
  • 177
  • 1
  • 13