I made a code that allows me to exchange messages between a client and a server. I run a while loop in the class server that checks whether the client has sent a packet to the server at this point call Checking() function.
This Checking() function allows me to control some of the specific client. But there is a problem, in particular the function call is inside the while loop, so even if the client doesn't send anything to the server, the code of course always call the Checking() function.
How can I avoid this callback redundant?
There would be something to see if indeed the client sent a message so as to structure a condition?
Problem Example:
While(true)
{
String messaggio = (new String(ricevuta.getData()).trim());
System.out.println("Client says: " + messaggio);
Checking();
}
console result:
Client says: hello
10
10
10
10
10
10
10
**infinite loop.**
What I thought:
if Client send something => run Checking(); function<br>
else continue;
Who can give me a help? Is there a method to do this on the UDP protocol?
The problem in your code is that it allows to receive a packet from
client only once as far now.
And, the while loop simply prints the data in the received packet. It does not seem to be receiving a new packet.
while(true)
{
String messaggio = (new String(ricevuta.getData()).trim());
System.out.println("Client says: " + messaggio);
Checking();
}
Instead it should be like the sample below:
byte[] receiveData = new byte[1024];
DatagramPacket ricevuta= new DatagramPacket(receiveData,receiveData.length);
while(true)
{
datagramSocket.receive(ricevuta); //waits here until any packet is received
String messaggio = (new String(ricevuta.getData()).trim());
System.out.println("Client says: " + messaggio);
Checking();
}
So, now in every iteration of the while loop, it waits until a datagram packet is received. Only then it prints its data and calls the checking() function
Related
I am trying to send receive data using a Python server and a Java client. First, Java sends a JSON in string to Python Server. After the string received, Python server will send a JSON back to the client. After the client receives the JSON from the server, it again sends a JSON in string to server. (Client sends the same message all the time) This is a recursive process.
ISSUE: After when I execute both Python server and Java, Python server receives the message sent by the Java Client and it sent back the JSON. But in the client side, the message sent by the server didnt receive.
Server.py
import socket
import threading
import json
import numpy
HEADER_INITIAL = 25
PORT = 1234
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
def handle_client(self, conn, addr):
print(f"[NEW CONNECTION] {addr} connected.")
connected = True
while connected:
msg = conn.recv(HEADER_INITIAL).decode(FORMAT)
if msg:
print("[DATA] RECEIVED"+ str(msg))
x = {
"Sentence": "This is a value"
}
y = json.dumps(x)
conn.send(y.encode(FORMAT))
conn.send("\n".encode(FORMAT));
conn.close()
Client.java
try (Socket socket = new Socket(Address, Port)) {
InputStream input = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);
int character;
StringBuilder data = new StringBuilder();
while(true){
Thread.sleep(4000);
String strJson = "{'message':'Hello World'}";
JSONObject jsonObj = new JSONObject(strJson);
writer.println(jsonObj.toString());
while((character = reader.read()) != -1) {
data.append((char) character);
}
System.out.println(data);
}
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
UPDATE
Here is the debug output.
I first started the server and then started client. Initially server receives the {'message':'Hello World'} value which is sent by the client and the server sends back the value of the x variable to the client. Then the server receives nothing from the client, but the client prints the value of x continuously.( System.out.println(data);) I tried to send dynamic values from the server to client, but the client prints only the value which is sent by the server in the first time.
You don't provide any debugging output so it's difficult to be 100% sure this is the entire cause. However, it seems pretty evident that this section of your client code isn't correct:
while((character = reader.read()) != -1) {
data.append((char) character);
}
System.out.println(data);
The server is holding the connection open forever (nothing ever sets connected to false). And so in the loop above, the character returned by reader.read will never be -1 because -1 is only returned at "end of stream". End of stream will only occur when the server closes its socket -- or is otherwise disconnected.
You should add a check for the newline to break out of the read loop:
if (character == '\n')
break;
or you could add it to the while condition:
while ((character = reader.read()) != -1 && character != '\n') {
...
Your code overall lacks appropriate handling of possible exceptional conditions. For example, if the client disconnects, your server will never exit its loop. It will call recv, get back an empty string (signifying "end of file" on the connection), and so will correctly bypass sending a response, but it will then simply go back and execute recv again, get an empty string again, and so forth forever.
Also, your python code makes the implicit assumption that the recv returns exactly the single string that was sent by the client, which is not guaranteed. If the client sends a 20 character string for example, it's possible that the first server recv call returns the first 10 characters, and the next call returns the rest.
(In practice, given the sleep in the client side code, that's unlikely to be a problem in this snippet of code, but one should program defensively because in a real production program, there will inevitably be a race or edge case that will do exactly this and it will cause the client and server to get out of sync and be difficult to debug.)
I have a java program, where a client will continuously send a number to a server, over and over, using sockets.
Usually the 'readObject' or 'writeObject' calls will sort of wait until the other side is ready to send or receive. But in my specific case here, the client will just skip over the writing to server, if the server is not currently reading.
Below is my client code. I have a Request class to send the information, which is just an integer in my case:
Socket socket = new Socket("localhost", 2910);
ObjectOutputStream outToServer = new ObjectOutputStream(socket.getOutputStream());
Random r = new Random();
while(true) {
Request request = new Request();
request.reqType = Request.TYPE.ADD;
request.add = r.nextInt(100);
System.out.println("Sending to server: " + request.add);
outToServer.writeObject(request);
Thread.sleep(100);
}
And here's the server part:
try {
ObjectInputStream inFromClient = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream outToClient = new ObjectOutputStream(socket.getOutputStream());
while(true) {
Request req = (Request)inFromClient.readObject();
switch (req.reqType) {
case ADD : {
Logger.getInstance().log(name + " added " + req.add);
serv.add(req.add);
break;
}
case RESULT : {
Logger.getInstance().log(name + " produced result " + req.result);
break;
}
case RETRIEVE : {
int[] retrieve = serv.retrieve();
Logger.getInstance().log(name + " retrieved: " + retrieve[0] + ", " + retrieve[1] + ", " + retrieve[2]);
outToClient.writeObject(new Request(retrieve));
break;
}
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
The above code is run in a Thread.
So the thing here is, my client send a Request object, and set the type to ADD. The server will read/receive the Request, and check the type, and find that it is ADD, so it will call 'serv.add'. This call may cause a "wait()" call, which means the Thread here is paused at this point, and, thus, stuck.
The client will attempt to send the next Request object, but because the server Thread is stuck on the 'serv.add' call, it appears the client doesn't write anything, and just skips the call, and does the while-loop over again.
So I'm attempting to send a bunch of Requests, which the server doesn't receive.
I hope it makes sense.
So I guess my question is:
If the server is not currently attempting to read from the client, and the client is attempting to write, will the 'writeObject' call sort of time out, and then just continue, or what's going on?
So for future reference.
The writeObject will just send a bunch of objects to the server. The readObject will read them at its own pace. There seems to be some kind of internal buffer in relation to the readObject.
My client sends 30 integers, the server reads 10, then wait()s. The client terminates. The server will at some point continue, and then read the rest of the sent objects.
So I don't loose anything.
Here is the flow of my client/server.
Socket is created in main thread.
Socket passes to Thread 1.
Client sends data to server
Server responds to client
Server closes input stream, output stream, and socket by invoking close()
Socket returned to main thread, and then passed to Thread 2.
Client writes data to server - no exception, no errors, server gets no data
Client attempts to read data - no exceptions, no errors
How can I detect the problem that socket was closed?
try {
os = new DataOutputStream(this.socket.getOutputStream());
os.write(data);
os.flush();
System.out.println("Written " + data.length + " bytes");
} catch (IOException e) {
System.out.println("Client failed to write to stream");
System.out.println(e.getMessage());
e.printStackTrace();
}
The exception is never thrown. It says Written 60 bytes. Any ideas?
UPDATE
Here is the way that I read the response. I wait for data, read first 4 bytes (which gives the the length of response), and keep reading until I read the specified length. This loop never ends because no data ever comes in.
is = new DataInputStream(this.socket.getInputStream());
while(true){
while(is.available() > 0){
bos.write(is.read());
}
if(contentLength == 0 && bos.size() > 3){
byte[] bytes = bos.toByteArray();
byte[] size = Arrays.copyOf(bytes, 4);
contentLength = ByteBuffer.wrap(size).getInt();
}
if(bos.size() - 4 < contentLength){
continue;
}
break;
}
When the server closes its end of the TCP connection, it sends a FIN packet to tell the client. The client program sees this as the InputStream reaching the end. Also, if the client tries to write the server will send an RST packet to signal error. If the client program tries to write after RST was received, the API will throw a SocketException with the message "connection reset."
Your problem is with detecting the end of the input here:
while(is.available() > 0){
bos.write(is.read());
}
The available method probably doesn't do what you think it does. If you want to read 4 bytes, read 4 bytes:
byte[] bytes = new byte[4];
is.readFully(bytes); // throws EOFException on end of input
It says that it wrote 60 bytes because it did. The server just isn't listening anymore. You need to get the input stream to see if anything is there. If nothing comes back, then you know that the connection didn't work.
UPDATE
Use a timer to determine if the server is responding.
Long currenttime = System.currentTimeMillis();
while(System.currentTimeMillis() - currentTime < x){ //x = miliseconds you want to wait
(try to read from server)
}
This way if it takes longer than x seconds, it will time out and you can do some error catching after the while loop
I have been dealing with one problem all day and I googled it in many different ways but I just can not find a solution, so I guest is time to ask:
I'm trying to code two apps: the client and the server with java using sockets and everything except one thing works fine: the client won't receive all the messages but only pair ones.
What I am doing is looping a 2D array to send every "x" time a message from the server to the client but for example if the loop send 8 messages the client only receive messages 2, 4, 6 and 8.
I printed in my server side console the output just as a verification that the array is property filled and the server display all the messages but not the client.
Im using this:
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF(getMACAddress());
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
while (true)
{
String input = in.readUTF();
if (input.equals("finish"))
{
System.out.println("Server has closed the connection\nGoodBye!");
System.exit(0);
}
else
{
System.out.println("Server says " + in.readUTF());
}
}
The problem is that you read input for comparison to "finish", and then you read a whole new string that you never compare.
Instead, you should print input in the else branch of the conditional, i.e.
while (true) {
String input = in.readUTF();
if (input.equals("finish")) {
System.out.println("Server has closed the connection\nGoodBye!");
System.exit(0);
} else {
System.out.println("Server says " + input);
// ^^^^^
}
}
I am implementing a really basic server-client model in Java, by using UDP sockets and I have come across a really strange issue.
All I want to do is let the user (client) send a message to the server and then the server will print it.
I have an example but I am missing something since I have the following issue:
If the client sends the message "a" to the server it gets received correctly.
If the client sends the message "bbb" to the server it gets received correctly.
If the client sends the message "c" to the server, then the server will print "cbb" as the received message.
It seems as if the server does clean some kind of buffer when it gets a new message.
This is the code I am using:
Server
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String args[]) throws Exception {
byte[] receive_data = new byte[256];
int recv_port;
DatagramSocket server_socket = new DatagramSocket(5000);
System.out.println("Server - Initialized server. Waiting for client on port 5000");
while (true) {
// System.out.println("Server - Listening for connections...");
DatagramPacket receive_packet = new DatagramPacket(receive_data, receive_data.length);
server_socket.receive(receive_packet);
String data = new String(receive_packet.getData());
InetAddress IPAddress = receive_packet.getAddress();
recv_port = receive_packet.getPort();
if (data.equals("q") || data.equals("Q")) {
System.out.println("Server - Exiting !");
break;
} else {
System.out.println("Server - Client from IP " + IPAddress + " # port " + recv_port + " said : " + data + " (length: " + receive_packet.getLength() + ")");
}
}
}
}
Client
public class UDPClient {
public static void main(String args[]) throws Exception {
byte[] send_data = new byte[256];
BufferedReader infromuser = new BufferedReader(new InputStreamReader(System.in));
DatagramSocket client_socket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("localhost");
System.out.println("Client - Initialized the client...");
while (true) {
System.out.print("Client - Type Something (q or Q to quit): ");
String data = infromuser.readLine();
if (data.equals("q") || data.equals("Q")) {
System.out.println("Client - Exited !");
DatagramPacket send_packet = new DatagramPacket(send_data, send_data.length, IPAddress, 5000);
System.out.println("Client - Sending data : <" + data + ">");
client_socket.send(send_packet);
break;
} else {
send_data = data.getBytes();
DatagramPacket send_packet = new DatagramPacket(send_data, send_data.length, IPAddress, 5000);
System.out.println("Client - Sending data : <" + data + ">");
client_socket.send(send_packet);
}
}
client_socket.close();
}
}
I suppose that the mistake is something trivial, but my skills in network programming are limited, therefore I don't know what exactly it is.
Just to make clear, I am running both the server and the client at the same machine (mac) on different terminals, just in case it affects the situation in anyway.
Any help would be greatly appreciated.
EDIT
...And I come back to answer my own question.
The problem was that I was not defining the amount of data that the server socket should expect to read.
Therefore when I change
String data = new String(receive_packet.getData());
with
String data = new String(receive_packet.getData(), 0, receive_packet.getLength());
everything worked smoothly.
Just for future reference and for people who might come across the same problem :)
When you're constructing the String based on the result, you're currently ignoring the length of the received packet.
After using DataSocket.receive(DatagramPacket), the length of the DatagramPacket should be set to the length that was actually received:
The length field of the datagram packet object contains the length of
the received message. If the message is longer than the packet's
length, the message is truncated.
This should fix the problem on the receiving side:
String data = new String(receive_packet.getData(), 0, receive_packet.getLength());
For this to work you also need to make sure the data sent is of the right size. In particular, don't use send_data.length to construct the outgoing DatagramPacket. This will always use the full length of the buffer). The length parameter isn't meant to be always send_data.length (otherwise the constructor would get it itself from the array), it's meant for the actual useful length of the message within that array.
On your first call this is what receive_data looks like:
--------------
|"a"| | |
--------------
On your second call:
--------------
|"b"|"b"| "b" | notice that the "a" in data_receive was overwritten
--------------
On your third call, you only send a single letter,
so the only part of the array that gets overwritten is the first element:
--------------
|"c"|"b"| "b" |
--------------
This is happening because there is still data left in the receive_data array in between messages to the server, a simple way around this would to just initialize a new array inside of you receive loop. That way every time you receive a message you will have a fresh array waiting for you.
while (true)
{
byte[] receive_data = new byte[256];
......
}
To solve the problem you should use length of receive_packet to create a String or array.
For higher performance in server side, it's better to initialize receive_packet before while section and reset its length at the end of while section to reuse it in loop : receive_packet.setLength(buffer.length);