Messages lost while using java sockets readUTF - java

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);
// ^^^^^
}
}

Related

Send message from Java client to Python server using sockets and vice versa

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.)

ObjectOutputStream.writeBytes(String s) unexpected output values

I am using an ObjectOutputStream object os to send a String msg from a client Android app to a c++ server.
I know how my msg must be received by the server:
each char of the msg is stored in a byte array (received_msg[]). I also know the exact msg the server expects (through another c++ app).
The data I send is a string made from 1 byte array and 2 other string.
My problem:
I already used PrintWriter to send my data, but my server would always display some weird char in received_msg, at index 24 to 28.
I tried a lot of conversions to fix it, but gave up on that.
So I tried sending msg with ObjectOutputStream.
With the client using ObjectOutputStream.writeBytes(), the server shows almost the right received message. Almost because there are characters that are added at the beginning.
Something like that :
In the server received_msg:
index 0: ┐
index 1: i
index 2: ''
index 3: |
index 4: I //beginning of the message I actually wanted to send
index 5: S //every char following index 4 is good.
while I expected and sent nothing before 'I''S'.
The message I send begins like that : ISOXXXXX
So I was wondering if there were any ways to retrieve the REAL output of ObjectOutputStream.writeBytes. I know that it's Output, not Input, still that would help me understand how it adds the weird header.
Thanks in advance for your suggestion
My send function
private void send(String o) {
System.out.println("socket");
try {
this.socket = new Socket(serverIP, portNumber);
os = new ObjectOutputStream(socket.getOutputStream());
//OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
//InputStreamReader in = new InputStreamReader(socket.getInputStream());
// PrintWriter pw = new PrintWriter(out, true);
System.out.println("Connected to server : " + this.socket.getInetAddress() + " on port " + this.socket.getPort());
System.out.println("from local address: " + this.socket.getLocalAddress() + " and port: " + this.socket.getLocalPort());
System.out.println("02. -> Sending an object...");
ArrayList<String> tempoStr = StringToByteArray(o);
String msg="";
for(String inStr :tempoStr)
msg+=inStr;
System.out.println("the message I ACTUALLY send is\n"+msg); //the result in console is EXACTLY the message I expect.
os.writeBytes(msg); //then when I check on the server: unexpected additionnal chars at the beginning.
os.flush();
// pw.write(msg);
//pw.flush();
System.out.println("send success");
} catch (IOException e) {
e.printStackTrace();
System.out.println("XX. Exception Occurred on Sending:" + e.toString() +"\n"+ e.getCause());
System.out.println("Socket creation failure or error on sending.");
}
}
PS: I cannot change the server code.
Do not use ObjectOutputStream (java only). One might use DataOutputStream, but here it seems you want something simple.
byte[] a = ...
String b = ...
OutputStream out = ...
out.write(a);
out.write((b + '\u0000').getBytes("UTF-8")); // Or "Windows-1252" / "ISO-8859-1"
out.flush();
I have added a '\0' as that is used in C/C++ to terminate strings (binary output).
Or maybe "\r\n" might be expected (text output).
The encoding is given explicitly.

how to tell server has sent data successfully in socket programming?

i am working on a problem on socket programming in JAVA.
There is a server and a client.
1) server is connected to client
2) server sends N no of Strings which are stored in an array on server side(obviously ;)).
3)Client doesn't know the size of array
4)Server receives Strings from server one by one.
5)When Client reads all the Strings it sends one msg to server
6)Server receives the msg.
7)This process goes on(step 2-step 6) for multiple times.
The problem i am facing is, Client does not know when server sends the last String and it is waiting for its turn.
I have solved this problem using:
a)Multi threading.
b)Telling size of array to client at the beginning of the first msg
I want to know is there any in-built function which indicates if the server has stoped sending data?
here is the code for 1 iteration(step 1-step 6)
Server code:
public class server {
static String[] a;
static DataOutputStream dos;
static DataInputStream dis;
static ServerSocket server;
static Socket socket;
public static void main(String[] args)
{
a=new String[]{"String1","String2","String3"};
try {
server=new ServerSocket(8080);
socket=server.accept();
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
///sending array values
//String temp=null;
for(int i=0;i<a.length;i++)
{
dos.writeUTF(a[i]);
}
String msg_from_client=dis.readUTF();
System.out.println(msg_from_client);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client code:
public class client {
static String[] a;
static DataOutputStream dos;
static DataInputStream dis;
static Socket socket;
static Scanner sc;
public static void main(String[] args)
{
try {
socket=new Socket("127.0.0.1",8080);
System.out.println("connected");
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
sc=new Scanner(System.in);
//reading from server i dont know what is the size of array at server side
String temp=null;
while((temp=dis.readUTF())!=null)
{
System.out.println(temp);
}
System.out.println("out of the loop");
////now client sends the msg;
String msg=sc.nextLine();
dos.writeUTF(msg);
System.out.println("sent");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
output at client side:
connected String1 String2 String3
This is the time to learn more about protocols. You can setup your own protocol between your server and client i.e., the first message from the server would always contain the # of strings to follow. The client would keep a note of it and then it will request for # of strings that server told in first method.
EDIT: Little more enhanced protocol
If you chose the path to open a new connection for each message as suggested by other user, then you would have to add a little more to your protocol. You would need
Client Information, so that server knows what communication it has done with this client previously
Message information, so that server knows if this client is asking for new message or it sent some message earlier to this client and he is asking for next part of this message.
1 can be achieved by allotting a client ID. If you know how many clients you are dealing with, you can have it a hardcoded value. Otherwise generate at runtime
2 Message information could be "null" indicating that the client is asking for "any new message" for him. Keep in mind that having a "null" message_id doesn't mean that you skip this field. You have to make sure you add "message_id" "key" in the request but keep that field empty. The reply to this request would be expected # of strings that server would be returning plus a newly generated message_id. The client will use this message_id in all subsequent calls and will tell the server, I am asking for string x of y from message_id z
You need absolutely to exchange one information between server and client to indicate end of transmission:
by sending number of message before: as you suggest;
by sending special message at the end "END" for example.
Another solution: instead of looping 6/7, close the connection when data is read, and connect again.

How to avoid call a function in redundancy

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

Java UDP socket - Data are left over at the server-side

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);

Categories

Resources