I am doing a simple Java Client application which should communicate with Python Server. I can easily send a string to Python Server and print it in console, but when i'm trying to use received string in IFs it never get into IF statement even if it should.
Here is Java Client send msg code
socket = new Socket(dstAddress, dstPort);
dataOutputStream = new DataOutputStream(
socket.getOutputStream());
dataInputStream = new DataInputStream(socket.getInputStream());
if(msgToServer != null){
dataOutputStream.writeUTF("UP");
}
System.out.println(dataInputStream.readLine());
And Python Server code:
import socket
HOST = ''
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
print 'Socket now listening'
conn, addr = s.accept()
print 'Connected to: ' + addr[0] + ':' + str(addr[1])
data = conn.recv(1024)
if data == "UP":
conn.sendall('Works')
else:
conn.sendall('Does not work')
conn.close()
s.close()
print data
So when i send to Python Server "UP" it should send back to Java Client "Works", but i reveive "Does not work" and in Python Server the output data is: "UP"
Why it isn't go into if statement?
The JavaDoc of DataOutputStream#writeUTF(...) says:
First, two bytes are written to the output stream as if by the
writeShort method giving the number of bytes to follow
In you python code your data value will be prefixed with two bytes for the length of the string to follow.
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 simple application which create a socket between java(server) and python(client).
The main function of the python code is to take data from user and send it to the server(java code)
here's the python code
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("localhost", 5000))
while True:
data = input("Enter data to send : ")
if(data == 'q'):
break
client_socket.sendall(data.encode('utf-8'))
client_socket.close()
and here's the java code
String fromclient;
ServerSocket Server = new ServerSocket (5000);
while(true)
{
Socket connected = Server.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader (connected.getInputStream()));
fromclient = inFromClient.readLine();
if ( fromclient.equals("q") ){
connected.close();
break;
}else {
System.out.println(fromclient);
}
}
when I write any text and click Enter, nothing goes to java code and nothing printed to the console, but when i send 'q' from python, the python code closed and all the data i wrote are now printed in java console.
I have no idea what is the reason of this, and how i can fix it.
The Java code waits for a line-break, but the Python part does not send one (input provides no line-break in the string it returns).
Try
client_socket.sendall((data+'\n').encode('utf-8'))
As #Kayaman suggests, the accept is in a wrong place (and also is the BufferedReader).
Socket connected = Server.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader (connected.getInputStream()));
while(true)
{
fromclient = inFromClient.readLine();
would be a better order.
Also, Python client does not send the 'q' in its current form. So the if with the fromclient.equals("q") will not close the socket, the code will just die on the next readLine() instead. Re-order the Python part too:
data = input("Enter data to send : ")
client_socket.sendall((data+'\n').encode('utf-8'))
if(data == 'q'):
break
Server in python
import socket
from sys import getsizeof
host = ''
port = 5560
storedValue = "Yo, what's up?"
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind comPlete.")
return s
def setupConnection():
s.listen(1) # Allows one connection at a time.
print("Waiting for client")
conn, address = s.accept()
return conn
def GET():
reply = storedValue
return reply
def REPEAT(dataMessage):
reply = dataMessage[1]
return reply
def dataTransfer(conn, s):
# A big loop that sends/receives data until told not to.
while True:
# Receive the data
data = conn.recv(1028) # receive the data
data = data.decode('utf-8')
data = data.strip()
print("data value from client: " + data)
# Split the data such that you separate the command
# from the rest of the data.
command = str(data)
print("data length from client: " + command)
reply = ""
if command == "GET":
reply = GET()
print (command)
print (reply)
elif command == 'REPEAT':
reply = REPEAT(dataMessage)
elif command == 'EXIT':
print("Our client has left us :(")
break
elif command == 'KILL':
print("Our server is shutting down.")
s.close()
break
else:
reply = 'Unknown Command'
# Send the reply back to the client
conn.sendall(bytes(reply, 'utf-8'))
print("Data has been sent!")
conn.close()
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn, s)
except:
break
Client in java
import java.io.*;
import java.net.*;
import java.util.*;
public class pcClient {
public static void main(String[] args) {
Socket rpiSocket = null;
DataInputStream in = null;
PrintStream out = null;
try {
rpiSocket = new Socket("localhost",5560);
out = new PrintStream(rpiSocket.getOutputStream());
in = new DataInputStream(new BufferedInputStream(rpiSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}
try {
if (rpiSocket != null && out != null && in != null) {
while(true) {
System.out.println("Please input your command ");
Scanner scanner = new Scanner(System.in);
String command = scanner.nextLine();
if(command.equals("KILL")) {
break;
}
System.out.println("Sending command to client: " + command);
out.println(command);
byte[] bytes = new byte[1024];
in.read(bytes);
String reply = new String(bytes, "UTF-8");
System.out.println("Reply from server: " + reply.trim());
}
}
rpiSocket.close();
System.out.println("Connections closed successfully");
}
catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
I have the python server above and a java client. The java client takes input from user and sends it to the python. All this is working well. However, the python server is receiving the string from the java and an additional empty string. For example, from the java client, when i send the word "GET", the python server is able to receive this GET and print "Yo, what's up?". However, it goes back to the "While True" and immediately also additionally receives an empty string right after and starts checking the condition with that empty string. I tried to trim the strings received from the java client. How can i solve this? Thanks.
The problem is occurring because of out.println(command) you are using from the java program. It is sending the command and also some newline characters over the socket. If you replace it with out.print(command), the problem will be solved.
println may be sending the main string and the newline characters internally in two calls, I am not sure. But ideally, every "command" from the client side should first include the length of the command string, and then the real command. Server side may need buffering or splitting of the input data if recv returns more than or less than the required number of bytes.
There is a small python library datachunkpy which may help to split and process the commands (https://pypi.python.org/pypi/datachunkpy/1.0.0)
conn.recv() returns as much data as immediately available (e.g. one packet). The Java runtime library on the other hand is free to subdivide the sent data into multiple packets. I guess that it sends one packet with the "GET" and another packet with the final newline.
A solution would be for the server to wait and collect input from stream until a newline is found to finish the command.
I made a python "queue" (similar to a JMS protocol) that will receive questions from two Java clients. The python-server will receive the message from one of the Java clients and the second one will read the question and post an answer. The connection and messaging works, the problem comes when a Java client answers with a String of great length.
The response received by python is incomplete! What is worse, the message is cut at a certain number of characters and always at the same length, but, that number is different if someone else hosts the server. (i.e.: friend1 hosts the server, friend2 sends response, length received: 1380chars. Friend2 hosts the server, friend1 posts the answer, length received: 1431chars) This is the server-side python code:
s = socket.socket()
host = socket.gethostname()
# host = "192.168.0.20"
port = 12345
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
# print 'Got connection from', addr
message = c.recv(8192) #Is this length a problem?
# print message
message = message.strip()
ipAddress = addr[0]
I read questions here on StackOverflow, that c.recv() should have no problem with a big number of bytes and our response is somewhere close to 1500 characters. This is the java client:
private void openConnection(){
try {
socket = new Socket(HOST, PORT);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
socketPregunta.getInputStream()));
stdIn = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e) {}
}
public void sendAnswer(String answer) throws IOException{
openConnection();
out.write("PUBLISH-" + answer); //This answer is send incomplete!
out.flush();
closeConnection();
}
Thanks in advance!
From the documentation:
recv(buffersize[, flags]) -> data
Receive up to buffersize bytes from the socket. For the optional
flags argument, see the Unix manual. When no data is available, block
until at least one byte is available or until the remote end is
closed. When the remote end is closed and all data is read, return
the empty string.
So recv() can return fewer bytes than you ask for, which is what's happening in your case. There is discussion of this in the socket howto.
Basically you need to keep calling recv() until you have received a complete message, or the remote peer has closed the connection (signalled by recv() returning an empty string). How you do that depends on your protocol. The options are:
use fixed sized messages
have some kind of delimiter or sentinel to detect end of message
have the client provide the message length as part of the message
have the client close the connection when it has finished sending a message. Obviously it will not be able to receive a response in this case.
Looking at your Java code, option 4 might work for you because it is sending a message and then closing the connection. This code should work:
s = socket.socket()
host = socket.gethostname()
# host = "192.168.0.20"
port = 12345
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
# print 'Got connection from', addr
message = []
chars_remaining = 8192
recv_buf = c.recv(chars_remaining)
while recv_buf:
message.append(recv_buf)
chars_remaining -= len(recv_buf)
if chars_remaining = 0:
print("Exhausted buffer")
break
recv_buf = c.recv(chars_remaining)
# print message
message = ''.join(message).strip()
ipAddress = addr[0]
My problem is that when i send data ( with socket.write()) from the nodejs server to the java client the java client is stuck in the datastream as long as there is no FIN packet( which would be send when i use socket.end() in nodejs) from the server.
My quesiton is now wether there is a way java can read it without the FIN package.
I thought there has to be a way because it works perfectly when you create a client with
the net module of NodeJS.
Server
var server = require("net").Server();
function cl(t){console.log(t)};
server.listen("5022","127.0.0.1", function(req,res){
cl("Server started...");
});
server.on("connection", function(socket){
var ip = socket.remoteAddress;
socket.setEncoding("utf8");
cl("connection --> "+ip);
socket.write("Welcome...");
socket.on("data",function(d){
var data = JSON.stringify(d);
cl("Data arrived "+data);
});
socket.on("end", function(){
cl("end");
})
socket.on("close",function(){
cl("Disconnect --> "+ip+"\n");
})
socket.on("error", function(err){
cl("ERROR "+err);
});
});
Note: So as is said, when i would add socket.end() a FIN packet would be send and the java client gets out of the datastream and returns the data. So at the moment i can send data from the server once in the entire session.
part of Client
Socket sc = new Socket(ip, port);
BufferedReader in = new BufferedReader(new
InputStreamReader(sc.getInputStream()));
DataOutputStream out = new DataOutputStream(sc.getOutputStream());
String input;
while(true)
{
while (!in.ready()) {Thread.sleep(2000);}
input = in.readLine();
System.out.println("Message : " + input);
out.writeUTF(input);
}
Note: Sending data to the server does work from this java client.
in.readLine() is doing just what it says, reading a line, which means it's looking for a newline character to know when to stop reading. So in your node code just append a \n when you .write() so that the Java code can resume. Example: socket.write("Welcome...\n");