Java storing BufferedOutputStream in array - java

In Java i am trying to store each BufferedOutputStream the server makes into an array aside from the threads in order to broadcast some data to all connected clients.
// initialisation
ArrayList<BufferedOutputStream> connections = new ArrayList<BufferedOutputStream>();
// when a client connects
Socket connection = socket.accept();
connections[id] = connection;
// broadcasting to all clients
for (int i = 0; i < connections.size(); i++) {
try {
OutputStreamWriter osw = new OutputStreamWriter(connections.get(i), "US-ASCII");
osw.write(s + "\n");
osw.flush();
} catch (Exception g) {
// catch
}
}
note: only the essential code is given
The problem: The broadcasting loop only broadcasts to the first in the loop, and sometimes the others as well. No error is thrown and the loop iteration as it should.
What is wrong and how do i fix it?
It's probably something obvious but i'm still a beginner..
Thanks!

We can't tell you exactly what is wrong because you've left out important parts of the code. However, if connections[id] = connection is throwing an NPE, that can only mean that connections is null. And, on the face of it, you don't appear to have initialized connections to a non-null value!
The fix is to initialize connections ... somewhere ... to an array of the appropriate size. However, that brings you other problems. What is an appropriate size for the array, and what what you are going t when id is larger than connections.length?
The root problem is an array is (probably) a poor choice for holding the connections ...

Maybe the socket has close, or the i index in the array is null, so the question is, why don't you utilize the List<OutputStream> over Socket[]?
with List<OutputStream> or List<OutputStreamWriter> you will not need to initialize the OutputStreamWriter every time you want to send some data.

somehow You should store client socket object.
whenever you want to broadcast, iterate over collection get socket, get ouput stream from that, and write to socket.
Its working for me properly.

EDIT: Socket[] array = new Socket[#];
You never initialize your array. That could be the problem.
But I suggest using either a List or a Map.
Apparently, I'm guessing you wanna store the socket in a way that you could retrieve it by a property later (name or ID). In this case, I suggest using a HashMap, with Integer as they key, and Socket as the value. This was, you can use map.get(ID);, and it'll return the socket you want.
You could try using a HashMap, maybe have a var for how many people are currently connected.
When someone logs in, do something like
public class Serer {
HashMap<Integer, Socket> list = new HashMap<Integer, Socket>();
static final int maxConnections = 100;
static int currentConnections = 0;
public Server() {
try {
ServerSocket socket = new ServerSocket(/*port#*/, maxConnections);
}catch(IOException e) { }
}
public void acceptConnections() {
while(currentConnections < maxConnections) {
list.put(currentConnections++, serversocket.accept());
}
}
public Socket getSocket(int ID) {
return list.get(ID);
}
public static void main(String[] args) {
new Server().acceptConnections();
}
This isn't tested, and I highly suggest putting the 'acceptConnections' in a thread, so the while loop isn't holding up your code. I didn't catch any exceptions, but hopefully this will give you an idea of using a HashMap to hold your sockets
Now, if you wanna send data to all the sockets, you would need to create an OutputStream for each socket. I suggest making a class (such as User.java), then when someone connects, make a new User, passing it the socket.
while(true) {
new User(ss.accept());
}
Then in your User.java, have something kind of like:
public class User {
ObjectOutputStream out;
ObjectInputStream in;
Socket socket;
public User(Socket socket) {
this.socket = socket;
initStream();
startChat();
}
public void initStream() {
try{
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputSTream(socket.getInputStream());
}catch(IOException e) { }
}
public void startChat() {
new Thread(new Runnable() {
public void run() {
String input;
try {
while((input = (String) in.readObject) != null) {
//this loop only triggers when something is retrieved through the input stream
Server.sendGlobalMessage(input); //can be done in different ways
//The reason why I call this statically from Server.java is because Server.java
//is the class that contains the HashMap, but that's up to you of where to put it.
//You could make the `HashMap` static, and make the sendGlobalMessage() in User.java
}
}catch(IOException | ClassNotFoundException e) { }
};).start();
}
Now finally for the sendGlobalMessage, you will need to either use an Iterator, or you can turn your hashmap into an array. This code is assuming that instead of using a HashMap for sockets, you pass the socket into a User class, then use the HashMap to store the user. (you need access to the output stream)
HashMap<Integer, User> list = new HashMap<Integer, User>();
public static void sendGlobalMessage(String message) {
for(User user : list.values().toArray(new User[list.size]) {
try {
user.out.writeObject(message);
user.out.flush();
}catch(IOException | ClassNotFoundException e) { }
}
}

Related

Client side is not sending message to server Java Socket

I am learning about sockets in java, but when I was running a program that sends messages from the client side to server side it doesn't show a message. If I enter some text on the client side it doesn't show up on the server side, but if I type endProcess it stops running. Which means that the message is going through it's just not showing up.
My Client.java code is here:
import java.net.*;
import java.io.*;
public class Client{
Socket soc;
DataInputStream dis;
DataOutputStream dos;
public Client(){
try{
soc = new Socket("(Address)",5000);
System.out.println("Connection Established");
dis = new DataInputStream(System.in);
dos = new DataOutputStream(soc.getOutputStream());
System.out.println("Streams connected");
}catch(UnknownHostException u){
System.out.println(u);
}catch(IOException i){
System.out.println(i);
}
String line = "";
while(!line.equals("endConnection")){
try{
line = dis.readUTF();
dos.writeUTF(line);
}catch(IOException i){
System.out.println(i);
}
}
try {
soc.close();
dis.close();
dos.close();
} catch (Exception e) {
System.out.println(e)
}
}
public static void main(String[] args) {
new Client();
}
}
Here is my Server.java code:
import java.net.*;
import java.io.*;
public class Server {
ServerSocket serSoc;
Socket soc;
DataInputStream dis;
public Server(){
try {
serSoc = new ServerSocket(5000);
System.out.println("Server Online");
soc = serSoc.accept();
System.out.println("Client Connected");
dis = new DataInputStream(new BufferedInputStream(soc.getInputStream()));
String line = "";
System.out.println("Waiting for input...");
while(!line.equals("endConnection")){
line = dis.readUTF();
System.out.println(line);
}
System.out.println("Client disconnected");
soc.close();
dis.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new Server();
}
}
There are many problems here.
Duplex protocol issues
line = dis.readUTF();
dos.writeUTF(line);
This isn't going to work; The dis.readUTF() line is going to block (freeze) until a line is read. The problem is, sometimes you have nothing to send in which case you want to read, and something you have nothing to read in which case you want to send. In practice you need to redesign this entirely; you need 2 threads. At which point you get into the issues of multicore, needing synchronization primitives and/or java.util.concurrent classes for all data that is shared between the 2 threads.
Alternatively, adopt a model that is strictly push or pull (where at any given time both parties already know who can send, and if the other party wants to send they simply cannot. For example, every party sends a simply 'NOTHING TO DO' message every second, trading places every time. This is quite an inefficient algorithm, of course. But could be written without involving multiple threads.
Flush and close issues
dos.writeUTF(line);
This doesn't actually send anything, or at least, isn't guaranteed to. To send any data on the internet, it gets wrapped in a packet which has lots of overhead. So, things are buffered until there's a full packet to send. Which means that line doesn't do anything. It just fills a buffer, no packets go out. You first need to close or flush. dos.flush() would help maybe. This is a big problem, because later you do:
soc.close();
dis.close();
dos.close();
You first close the socket, which, well, closes the socket. You then close the streams, which will also send anything that's still stuck in a buffer, except, that will fail, because the socket is already closed. In other words, the line you .writeUTF()-ed? It never gets there. You first shove it in a buffer, then you close the socket, then you send the buffer which won't work as the socket is already closed.
Broken error handling
} catch (Exception e) {
System.out.println(e);
}
Horrible. Don't do this. Your code reacts to any problem by printing something and just keeping right on going. That means if anything goes wrong, the client will start spamming an endless cavalcade of exception traces and locking up the system with any luck. You want the code to stop running when problems occur. Easiest way, by far, is to just stick throws IOException on your constructor and main method, which is allowed. Distant second best option is to configure your 'eh whatever' catch blocks as throw new RuntimeException("unhandled", e); instead of e.printStackTrace().
What you do (System.out.println(e);) is even worse - you are tossing away extremely useful information such as the stack trace and causal chain.

Same TCP Socket (client-side) with two different scanners and two different BufferedReader

how can I download strings with two different objects BufferedReader and two different objects Scanner from a single socket with two different threads?
I already tried this solution below but myReader1, after reading from Socket, is with invalid characters how can I fix? You might suggest a workaround? Thanks a lot in advance
//Socket TCP declaration
InetAddress serverAddr = InetAddress.getByName(IP);
try
{
Socket mySocket = new Socket(serverAddr, PORT);
}
catch(Exception e)
{
e.printStackTrace();
}
//Thread 1
Thread t1 = new Thread(new Runnable()
{
#Override
public void run()
{
BufferedReader myReader1 = new BufferedReader(new InputStreamReader(mySocket.getInputStream(), "UTF-8"));
Scanner myScanner1 = new Scanner(myReader1).useDelimiter("\0");
synchronized(mySocket)
{
while(mySocket.isConnected() && myScanner1.hasNext())
{
String s = myScanner1.next();
}
}
}
});
Thread t2 = new Thread(new Runnable()
{
#Override
public void run()
{
BufferedReader myReader2 = new BufferedReader(new InputStreamReader(mySocket.getInputStream(), "UTF-8"));
Scanner myScanner2 = new Scanner(myReader2).useDelimiter("\0");
synchronized(mySocket)
{
while(mySocket.isConnected() && myScanner2.hasNext())
{
String s = myScanner2.next();
}
}
}
});
t1.start();
t2.start();
how can I download strings with two different objects BufferedReader and two different objects Scanner from a single socket with two different threads?
You can't .
You will never get this to work. Because of aspects of TCP you can't control, the data will arrive in unpredictable quanta, and the BufferedReaders will steal it from each other in unpredictable ways. Ditto the Scanners themselves if they have internal buffering.
In any case what you are trying to do has no actual meaning. What are you expecting the two threads to do that a single thread won't? If for example you're expecting them to read alternately, they won't. If you're expecting to be able to confidently send one string intended for thread 1 and another string intended for thread 2, you can't. It is impossible.
I already tried this solution below but myReader1, after reading from Socket, is with invalid characters how can I fix? You might suggest a workaround?
You won't succeed in getting anything working at all along the lines you've started on, but the basis of any solution must be a single Scanner and a single BufferedReader per socket. If you must have two threads you will need two sockets, with a BufferedReader and Scanner each.
try
{
Socket mySocket = new Socket(serverAddr, PORT);
}
catch(Exception e)
{
e.printStackTrace();
}
Don't write code like this. First, you should only be catching IOException. Second, all the code that depends on the success of this code should be logically inside this try block. It should be impossible for any code anywhere to access the mySocket variable unless this code has succeeded.
while(mySocket.isConnected() && myScanner1.hasNext())
The isConnected() test is pointless here. It will never return false. It doesn't magically become false when the peer disconnects.

What type of array do I send to constructor?

I am creating a server-chat-client application and have borrowed code. I know how most of the things work except one.
In my Class Server I wait for a socket to be accepted.
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
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();
System.out.println("Client have connected from:" + clientSocket.getLocalAddress().getHostName());
} 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
}
}
So if a socket gets accepted I create a thread class called Class ClientThread
To create a object of this class I need a socket and a array.
This is how my ClientThread class looks like
public class ClientThread extends Thread {
private ClientThread[] clientsConnected;
private Socket SOCKET = null;
private DataInputStream IN = null;
private DataOutputStream OUT = null;
private String userName,zone;
//-------------------------------------------------------
//Constructor
public ClientThread(Socket socket, ClientThread[] clientThread) {
this.SOCKET = socket;
this.clientsConnected = clientThread;
}
//Some more code
Now this is where I am lost. Do I send in my whole array? and if I do shouldn't user1 only get an array with 1 user and when user2 connects shouldn't he get an array with 2 users? I am lost. If someone could point me to something that explains this I would be grateful.
Your code will serve only 20 requests. For each one it adds new value to clientsContected, once the whole table is full it will just go back to the start of the loop (without closing the accepted connection).
Probably the idea of passing the clientsConnected to the thread, was so it can set the value to null once it stopped working (so that your main code in the loop can assigne a new client to it). GUessin as no code is included). But for that an index inside the array would be useful (so 3 parameters instead of 2) so the ClientThread doesn't have to search the whole array to find object matching this.
I would rather recommend using BlockingQueue (with limited capacity for example 5) to which you will pass accepted connections. Once it is full your main will be forced to wait on it till it has same space to insert new connection so you will stop accepting new sockets. Create the 20 threads, that in a inifinite loop tries to get a socket from that queue and serve it. Once they finish they go back an wait for new request.
So yes you passs the whole array.
Still it doesn't solve the problem of what happens if all are busy, as you keep accepting new clients instead of waiting for free Thread.

Java client server application, can't send an ArrayList

I searched the internet and i didn't find something for my question.
I have my client class, my server class and a Loc class. In my client class, i have a Jtext field, that i want to populate with values (free/occupied) depending if the seat is free or not.
In my server class i populate an ArrayList with all the seats free. I want to pass this ArrayList to my client and in the same time to display something like FREE FREE OCCUPIED.
But i can only pass my first value.
Here is the server class:
public static void main(String [] args){
ServerSocket client = null;
Loc l = new Loc();
try {
ArrayList<Loc> lista = new ArrayList<>();
for (int i=0;i<7;i++)
for(int j=0;j<6;j++)
{
l.setLoc(i);
l.setRand(j);
lista.add(l);
}
client = new ServerSocket(9000);
Socket socket = client.accept();
ObjectInputStream dis = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream dos = new ObjectOutputStream(socket.getOutputStream());
l = (Loc) dis.readObject();
System.out.println(l.getRand());
// Loc a = new Loc("ags",2, 42, 125);
dos.writeObject(lista);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
And here is my client class:
public class Client_Gui extends javax.swing.JFrame {
Socket socket = null;
ObjectOutputStream dos = null;
ObjectInputStream dis= null;
// ObjectOutputStream dos = null;
ArrayList<Loc> lst = new ArrayList<>();
Loc locul = new Loc();
/**
* Creates new form Client_Gui
*/
public Client_Gui() {
initComponents();
Loc loc = new Loc();
try {
ArrayList<Loc> lst = null;
socket = new Socket("localhost",9000);
dos = new ObjectOutputStream(socket.getOutputStream());
dis = new ObjectInputStream(socket.getInputStream());
dos.writeObject(loc);
lst = (ArrayList<Loc>) dis.readObject();
for(Loc a : lst){
if(a.getIdSpectator().equals("") == true)
txt_area.setText("Liber");
else
txt_area.setText("Ocupat");
}
} catch (IOException ex) {
Logger.getLogger(Client_Gui.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Client_Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
And another question related to this. Can i run my client/server application without sending first some information from the client? I mean, at first i tried to read from client first and then write to server but i got errors. After i changed, and first i write from client and then read, works normally, until it reaches that part with ArrayList.
EDIT: i tried to hard code and in my Client class i put the array list created by code.
Now, when i want to show it in the text field, still only the first value is displayed. Is my syntax wrong?
i used:
for(Loc a : lista){
if(a.getIdSpectator().equals("") == true)
txt_area.setText("Liber");
else
txt_area.setText("Ocupat ");
}
EDIT2: Jasper was right. I used append and now it works. Thanks.
Take a look at how you are constructing the list on the server....
ArrayList<Loc> lista = new ArrayList<>();
for (int i=0;i<7;i++)
for(int j=0;j<6;j++)
{
l.setLoc(i);
l.setRand(j);
lista.add(l);
}
Basically, all this is doing is adding the same instance of l to the array list, but on each loop, you are changing its properties. This means, you'll end up with a list of the same object with the same properties (cause it's just the single instance of the object)
What you should be doing is on each iteration of your loop is creating a new instance of what ever l is, setting its properties according only and that to the list
Updated
Okay, on client, you're setting the text of the JTextArea using
for(Loc a : lst){
if(a.getIdSpectator().equals("") == true)
txt_area.setText("Liber");
else
txt_area.setText("Ocupat");
}
setText replaces the contents of the field with the supplied text. Instead, you want to try using append
for(Loc a : lst){
if(a.getIdSpectator().equals("") == true)
txt_area.append("Liber");
else
txt_area.append("Ocupat");
}
Having said that, I would highly recommend that you consider taking a look at How to Use Tables and How to Use Lists for components that are better suited to display this type of data
You need to put it in a loop so all of your values passed from the socket will be recieve by the server not just the first value you send.
example:
in server
ObjectOutputStream dos = new ObjectOutputStream(socket.getOutputStream());
dos.writeObject(lista);
while(true)
{
l = (Loc) dis.readObject();
System.out.println(l.getRand());
// Loc a = new Loc("ags",2, 42, 125);
}
in client
dis = new ObjectInputStream(socket.getInputStream());
lst = (ArrayList<Loc>) dis.readObject();
for(Loc a : lst){
if(a.getIdSpectator().equals("") == true)
txt_area.setText("Liber");
else
txt_area.setText("Ocupat");
}
your question:
Can i run my client/server application without sending first some information from the client?
just always remember when you are trying to read data packet, someone should write data first.

Narrow communication to a specific client in chat application java

I just created an java chat application that allow a communication between many clients, however, i would like also to have the ability to one client send a message to a specific client, the others client cannot be able to see the message send, just like one client whispering to another one. Thank you in advance.
Here some part of my client
public void sendListener(){
writer.println(clientName2+" : "+broadcastTF.getText() );
writer.flush();
broadcastTF.setText("");
broadcastTF.requestFocus();
}
public class listenServer implements Runnable{
public void run(){
try{
String text;
while((text = reader.nextLine()) != null){
messageTA.append(text+ "\n");
}
}catch(Exception ex){}
}
}
private void setupServer(){
try{
socket = new Socket("127.0.0.1", 7894);
writer = new PrintWriter(socket.getOutputStream());
reader = new Scanner(socket.getInputStream());
listenServer ls = new listenServer();
Thread t = new Thread(ls);
t.start();
}
catch(Exception ex){
}
}
Here some part of my server
public class listenToClient implements Runnable{
Scanner reader;
public listenToClient(Socket socket){
try{
reader = new Scanner(socket.getInputStream());
}catch (Exception ex){}
}
public void run(){
try{
String text;
while((text = reader.nextLine()) != null){
sendToAll(text);
}
}catch(Exception ex){}
}
public void sendToAll(String text){
for (PrintWriter w : writers){
try{
w.println(text);
w.flush();
}catch(Exception ex){}
}
}
}
I think this is less related to specific code, and more related to overall design.
Primarily, you'd need some way of identifying individual clients. If you need fast lookups, you would use some sort of key/value map to store your writers, with the unique ID (user name, user ID, some random string, or whatever suits your situation) as the key. If that's not a concern, then you can store your client connections in a simple numerical array (or array-like structure) and iterate over until you find the target, then send to exclusively that connection.
Then, the sending client needs to be able to discern what its target is, and also have some way of sending the target information along with the message. Simply reading input at the server and echoing it out will not suffice for this - you'll have to do some amount of parsing, and you'll probably need to design some format for arranging that information.
As an example, one client-server communication format I designed had the first byte of a message be the length of the key in a key/value pair. The server would read the first byte, then read the next N bytes as the key. The remaining bytes were then known to be the value. In your case, a key length of 0 would mean it's not going to one specific destination, but to everyone.
Create a collection of clients such as hashmap. So whenever you get a new client connection accept, assign this client an id and put its socket reference against the id in the hashmap.
Clients should know each other ids to make sure that they can identify and send the messages to each other. So whenever a client sends a packet to server and it contains a recepient client id, server should lookup the hashmap. The recepient socket reference should be retrieved and message should be sent using the writer.
Hope it helps!

Categories