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.
Related
I am quite new to Java programming. For now I am studying source code of an android app called Evercam. However, I have a problem understanding a part of the code which involves while(true) loop.
Here is the snippet of the code:
while (true)
{
while (true)
{
byte[] responseMessageByteArray = new byte[4000];
DatagramPacket datagramPacketRecieve = new DatagramPacket(responseMessageByteArray, responseMessageByteArray.length);
datagramSocket.receive(datagramPacketRecieve);
String responseMessage = new String(datagramPacketRecieve.getData());
EvercamDiscover.printLogMessage("\nResponse Message:\n" + responseMessage);
StringReader stringReader = new StringReader(responseMessage);
InputNode localInputNode = NodeBuilder.read(stringReader);
EnvelopeProbeMatches localEnvelopeProbeMatches = (EnvelopeProbeMatches)(new Persister()).read(EnvelopeProbeMatches.class, localInputNode);
if (localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches.size() > 0)
{
ProbeMatch localProbeMatch = (ProbeMatch) localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches.get(0);
if (uuidArrayList.contains(localProbeMatch.EndpointReference.Address))
{
EvercamDiscover.printLogMessage("ONVIFDiscovery: Address " + localProbeMatch.EndpointReference.Address + " already added");
}
else
{
uuidArrayList.add(localProbeMatch.EndpointReference.Address);
DiscoveredCamera discoveredCamera = getCameraFromProbeMatch(localProbeMatch);
if (discoveredCamera.hasValidIpv4Address())
{
this.onActiveOnvifDevice(discoveredCamera);
cameraList.add(discoveredCamera);
}
}
}
}
}
Doesn't this create an infinite loop? My fundamentals in Java isn't strong, so I would be so grateful if anyone can tell in in what instances will a while(true){//codes} actually exits without any break or does it ever exit??
EDIT
My bad for actually extracting this snippet from decompiling directly from the android project files. I did not know that it would be different, and then again, I know very little. Here is the original code:
public ArrayList<DiscoveredCamera> probe() {
ArrayList<DiscoveredCamera> cameraList = new ArrayList<DiscoveredCamera>();
try {
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.setSoTimeout(SOCKET_TIMEOUT);
InetAddress multicastAddress = InetAddress.getByName(PROBE_IP);
if (multicastAddress == null) {
// System.out.println("InetAddress.getByName() for multicast returns null");
return cameraList;
}
// Send the UDP probe message
String soapMessage = getProbeSoapMessage();
// System.out.println(soapMessage);
byte[] soapMessageByteArray = soapMessage.getBytes();
DatagramPacket datagramPacketSend = new DatagramPacket(
soapMessageByteArray, soapMessageByteArray.length,
multicastAddress, PROBE_PORT);
datagramSocket.send(datagramPacketSend);
ArrayList<String> uuidArrayList = new ArrayList<String>();
while (true) {
// System.out.println("Receiving...");
byte[] responseMessageByteArray = new byte[4000];
DatagramPacket datagramPacketRecieve = new DatagramPacket(
responseMessageByteArray,
responseMessageByteArray.length);
datagramSocket.receive(datagramPacketRecieve);
String responseMessage = new String(
datagramPacketRecieve.getData());
EvercamDiscover.printLogMessage("\nResponse Message:\n"
+ responseMessage);
StringReader stringReader = new StringReader(responseMessage);
InputNode localInputNode = NodeBuilder.read(stringReader);
EnvelopeProbeMatches localEnvelopeProbeMatches = new Persister()
.read(EnvelopeProbeMatches.class, localInputNode);
if (localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches
.size() <= 0) {
continue;
}
ProbeMatch localProbeMatch = localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches
.get(0);
// EvercamDiscover.printLogMessage("Probe matches with UUID:\n"
// +
// localProbeMatch.EndpointReference.Address + " URL: " +
// localProbeMatch.XAddrs);
if (uuidArrayList
.contains(localProbeMatch.EndpointReference.Address)) {
EvercamDiscover.printLogMessage("ONVIFDiscovery: Address "
+ localProbeMatch.EndpointReference.Address
+ " already added");
continue;
}
uuidArrayList.add(localProbeMatch.EndpointReference.Address);
DiscoveredCamera discoveredCamera = getCameraFromProbeMatch(localProbeMatch);
if (discoveredCamera.hasValidIpv4Address()) {
onActiveOnvifDevice(discoveredCamera);
cameraList.add(discoveredCamera);
}
}
} catch (Exception e) {
// ONVIF timeout. Don't print anything.
}
Turns out there is continue statement in the actual code. Thank you so much for the response, I will remember that de-compiled classes should not be depended on.
This looks like an infinite loop. To be absolutely sure, you would have to statically read every statement and follow invoked methods to see if any possible invocations like Activity#finish() or Service#stopSelf() exists which would finish the currently running activity, effectively breaking the loop.
Another possibility is that the code is intended to be running in an infinite loop as a background thread service, and some other component would have an option to kill that service when it reaches a certain condition. For example, it could be part of a Runnable class and executed in a thread pool, and when a timeout exists, the pool is shut down.
the only possible way to exit from while loop is if one of the methods being called in loop throws exception. check code of these methods for exception or share it here
Infinite loops without any breaks could be useful for a Service running in background.
You create a new Thread doing the service infinitely thanks to a while(true) and when you stop your application you simply kill the process corresponding to the service.
My program is basically:
Client sends a String to Server,
Based on this String, Server is creating an ArrayList,
ArrayList is sent back to the Client.
What is failing here is:
After Client sends a String, the Server receives it and doesn't do anything else. In this time Client keeps on working and gets a NullPointer.
Client side:
public static ArrayList<String> sendStringToServer(String report) {
Socket socket;
ArrayList<String> fieldsList = new ArrayList<String>();
try {
socket = new Socket("localhost", 2345);
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os, true);
ps.println(report);
ps.flush();
//Here the debugger should stop and wait for server to create a List
//at this point there is no answer, code breaks
ObjectInputStream objectInput = new ObjectInputStream(socket.getInputStream());
Object object = objectInput.readObject();
fieldsList = (ArrayList<String>) object;
socket.close();
return fieldsList;
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Server side:
public class Server {
private ServerSocket serverSocket;
private Socket clientSocket;
private String telegram;
private StringBuilder telegramSB;
public static void main(String[] args) throws IOException, JRException {
new Server();
}
public Server() {
try {
serverSocket = new ServerSocket(2345);
while (true) {
clientSocket = serverSocket.accept();
InputStream is = clientSocket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
//debugger goes to here and then stops
telegram = br.readLine();
int counter = 0;
boolean startSeq = false;
for (char ch : telegram.toCharArray()) {
if (counter == 0 && ch == '/') {
startSeq = true;
}
if (startSeq == true) {
telegramSB = new StringBuilder();
telegramSB.append(ch);
}
if (ch == '\n') {
if (telegram.length() < 255) {
sendListWithFields();
} else {
new Launcher(telegram).run();
}
}
counter++;
}
} catch (JRException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
System.out.println(e);
}
}
My guess here would be that the BufferedReader is waiting to fill its buffer and you haven't sent enough data for it to do that and return so its waiting for more data to come through that never does (because your clients stops writing and starts to read). You could test this theory temporarily by dumping a load more data into the OutputStream on the client and flushing it.
If the above is the case then you probably want to not use BufferedReader but you have other issues here which also mean you probably want to avoid using PrintStream and BufferedReader for communication and serialisation anyway. For example the default character encoding on two different machines and JVMs could be different. When you create your PrintStream and InputStreamReader you don't specify a character encoding so they could end up being mismatched and the string that you write (including the newline character) could end up being understood completely differently by the remote side, this could also be a reason why its blocking (the client side encodes the newline character in one way but the server is expecting it to be encoded a completely different way), though less likely I think .
If you don't have to use PrintStream then I would suggest instead using DataOutputStream / DataInputStream:
//Client
BufferedOutputStream bufout = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dout = new DataOutputStream(bufout);
dout.writeUTF(report);
dout.flush();
//Server
BufferedInputStream bufin = new BufferedInputStream(socket.getInputStream());
DataInputStream din = new DataInputStream(bufin);
String report = din.readUTF();
You still get buffering from the BufferedIn/OutputStreams so it will be performant but the DataIn/OutputStreams will manage termination of variable length objects for you - they will send a length prefixing the string to tell the other side exactly how many bytes to read, so you don't need to use a special character to terminate the string you wrote, and this also means it doesn't matter what the content of your String is. In your example above even if it was working if your String had a newline character in it the server would read up until that first newline character, not to the end of the string you sent and that would put them out of sync for the next send/receive along that stream.
Using write/readUTF also specifies an encoding (UTF-8) so there is no mismatch there either.
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) { }
}
}
I have a function
public void loadUserOnline() {
try {
oos.writeObject(req); //Send request to Server to get online users
oos.flush();
LinkedList<UserOnlineInfo> userOnlineInfoList = (LinkedList<UserOnlineInfo>)ois.readObject(); // read object from Server contains online users
Vector<String> listData = new Vector<>(); // a Vector for JList
for (int i = 0; i < userOnlineInfoList.size(); i++) {
listData.add(userOnlineInfoList.get(i).getUser() + " --- " + userOnlineInfoList.get(i).getStatus()); // add elements to Vector
}
theList.setListData(listData); // set data source for JList
}
catch (Exception e){
e.printStackTrace();
}
}
The first time I call this function, it gets data from a server. Then data from the server changes. I call this function a second time, and the data is the same as the first time. Why?
You need to call ObjectOutputStream.reset() every time you want to resend the same object with new values, or else use writeUnshared(). See the Javadoc.
You're using the same ObjectOutputStream instance, oos, which has been exhausted by the first call to this method. If you initialise your ObjectOutputStream again then you'll get a new stream:
public void loadUserOnline() {
// initialise oos here or before the call to this method
ObjectOutputStream oos = new ObjectOutputStream(......
try {
oos.writeObject(req);
....
I'm having a little trouble with a simple Java server, client application.
Basically the topics says it all: when I do a writeUTF on the server side it only sends every 2nd time it's being executed.
For an example:
Server:
public class Server {
/**
* #param args
*/
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(7777);
Socket client = server.accept();
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
DataInputStream in = new DataInputStream(new BufferedInputStream(client.getInputStream()));
while(true) {
for(int i = 0; i < 100; i++) {
out.writeUTF("Test" + i);
out.flush();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And client:
public class Client {
/**
* #param args
*/
public static void main(String[] args) {
try {
Socket client = new Socket("localhost", 7777);
DataInputStream in = new DataInputStream(new BufferedInputStream(client.getInputStream()));
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
while(in.readUTF() != null) {
System.out.println(in.readUTF());
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And the output in the console looks like this:
Test1
Test3
Test5
Test7
Test9
Test11
What is causing this behavior?
It's because you're discarding data on your client.
When you check while(in.readUTF() != null), you're reading an entry from the stream every time to see if it's non-null. Then you discard this value, and read a new one within the loop. (As well as losing values, this has the bug that with an odd number of total values, the while condition will evaluate to true but the next call to readUTF() would return null within the loop.)
To fix this, you should read the value to a variable, and test this before using it - something like the following:
String value;
while((value = in.readUTF()) != null) {
System.out.println(value);
}
If you don't like the assignment and nullity check as a single expression, you can instead assign value = in.readUTF() initially and at the end of every loop, but personally I find this more error-prone.
This loop
while(in.readUTF() != null) {
System.out.println(in.readUTF());
}
throws away every second string it reads. You read one string while testing for end of file, discard it, then read another one and print it.
You are consuming the data in the while loop evaluation here:
while(in.readUTF() != null) {
System.out.println(in.readUTF());
}
Try this instead:
String line;
while( ((line = in.readUTF()) != null) {
System.out.println(line);
}
If you want your socket in UTF-8
you only need to add "UTF-8" in BufferedWriter and BufferedReader's contstructor
here is the sample
this.basicReader = this.Client.getInputStream();
this.basicWriter = this.Client.getOutputStream();
this.Reader= new BufferedReader(new InputStreamReader(basicReader,"UTF-8"));
this.Writer= new BufferedWriter(new OutputStreamWriter(basicWriter,"UTF-8"));
how to send data
this.Writer.write("data"+"\r\n");
this.Writer.flush();
and your main problem is your client didnt respond a msg when your client receive a msg
server to client
client to server
server to client
like this, try it.