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.
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 am trying to make two processes communicate through local sockets: a Python server and a Java client. The data I want to pass between both consists of the bytes of a Protobuf object, with variable size. I want the connection to remain open and be used until the end of the program, because I'm passing a lot of objects that need to be processed.
Because Protobuf objects have variable size, I am sending the size of the message/response before sending the true message/response containing the object.
Currently, I am using a TCPServer from the socketserver library on the Python side. I have the following handler implemented:
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def recv_all(self, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = self.request.recv(n - len(data))
if not packet:
return None
data += packet
return data
def handle(self):
logger.debug("Beginning of handle cycle for client: {}.".format(self.client_address))
while True:
if True: # please disregard this if condition
# Receive 4 bytes (1 int) denoting the size of the message
data_length_bytes: bytes = self.recv_all(4)
logger.debug('Received data_length: {}'.format(data_length_bytes))
# If recv read an empty request b'', then client has closed the connection
if not data_length_bytes:
break
data_length: int = int.from_bytes(data_length_bytes.strip(), byteorder='big')
data: bytes = self.recv_all(data_length).strip()
response: bytes = data.upper()
# Send length of response first
self.request.sendall(len(response).to_bytes(4, byteorder='big'))
# Send response
self.request.sendall(response)
logger.debug(
'Sent response to: {}. Size of response: {} bytes. Response: {}.'.format(self.client_address,
len(response),
response))
logger.debug("End of handle cycle for client: {}.".format(self.client_address))
And the following client:
class SocketClient
{
private static Socket socket;
private int port;
private DataOutputStream out;
private DataInputStream in;
SocketClient(int port)
{
this.port = port;
this.createSocket();
}
private void createSocket() {
InetAddress address;
try {
address = InetAddress.getByName("localhost");
socket = new Socket(address, port);
this.out = new DataOutputStream(socket.getOutputStream());
this.in = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] sendMessageAndReceiveResponse(byte[] messageToSend){
try {
if(true) { // again, please disregard this condition
//Send the size of the message to the server
this.out.writeInt(messageToSend.length);
out.flush();
this.out.write(messageToSend);
out.flush();
//Get the response message from the server
int length = in.readInt(); // read length of incoming message
byte[] buffer = null;
if(length>=0) {
buffer = new byte[length];
in.readFully(buffer, 0, buffer.length); // read the message
}
return buffer;
}
}
catch (ConnectException exception) {
System.out.println("ATTENTION! Could not connect to socket. Nothing was retrieved from the Python module.");
exception.printStackTrace();
return null;
}
catch (Exception exception)
{
exception.printStackTrace();
return null;
}
}
void close(){
//Closing the socket
try
{
in.close();
out.close();
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
I run the following experiment after starting the Python server:
SocketClient socketClient = new SocketClient(5000);
byte[] response;
// Case 1
response = socketClient.sendMessageAndReceiveResponse("12345678".getBytes());
System.out.println(new String(response));
// Case 2
response = socketClient.sendMessageAndReceiveResponse("123456781".getBytes());
System.out.println(new String(response));
// Case 3
response = socketClient.sendMessageAndReceiveResponse("12345678123456781".getBytes());
System.out.println(new String(response));
socketClient.close();
Case 1 and case 3 work well. However, when I run case 2, on the Python server side, I get the following log:
DEBUG -- [handle()] Received data_length: b'\x00\x00\x00\t' # The '\t' shouldn't be here. A '\x09' should.
And then the server throws and exception and exits the connection. This happens with every string with 8 < length < 14. What am I doing wrong, and is there an easier way to achieve what I want?
I figured out why I was having problems with messages of 8 < length < 14.
I was getting the \t character when length was equal to 9. I noticed that if I changed the length to 10, it would become \n. And to 13, \r. I realized that there wasn't any \t magically appearing. Python was for some reason converting \x09 to \t, because the horizontal tab character \t has an ASCII code equal to 9!
And when I applied the strip() function in this line:
data_length: int = int.from_bytes(data_length_bytes.strip(), byteorder='big')
, Python deleted my \t, which was actually my \x09. My problem was logging the value before stripping it, and so I took a long time to figure out my mistake.
Therefore the solution was to simply not use strip(). I leave here my current working code (at least for my tests), for someone to use:
Python server handler:
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def recv_all(self, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = self.request.recv(n - len(data))
if not packet:
return None
data += packet
return data
def handle(self):
while True:
data_length_bytes: bytes = self.recv_all(4)
# If recv read an empty request b'', then client has closed the connection
if not data_length_bytes:
break
# DON'T DO strip() ON THE DATA_LENGTH PACKET. It might delete what Python thinks is whitespace but
# it actually is a byte that makes part of the integer.
data_length: int = int.from_bytes(data_length_bytes, byteorder='big')
# Don't do strip() on data either (be sure to check if there is some error if you do use)
data: bytes = self.recv_all(data_length)
response: bytes = data.upper()
self.request.sendall(len(response).to_bytes(4, byteorder='big'))
self.request.sendall(response)
The Java client remained the same, but without that if(true) condition that I was using for debug reasons.
This is client code in Java
public static void main(String[] args) {
Socket rpiSocket = null;
DataInputStream in = null;
PrintStream out = null;
String str="Akif";
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.print(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);
}
}
This is server code in Python
import socket
from sys import getsizeof
host = ''
#host = '192.168.2.181'
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('akif')
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
Server and client working perfectly on localhost on my computer(win 10 pro). But if i run client on Win 10 PC and run server on Rpi PC, server working perfectly but client working until this line "in.read(bytes);" and it staying here.
P.S. = I tried turn of Windows firewall and Windows Defender. I used
wifi connection and I tried turned of modem firewall
What can i do to solve this. Thanks.
I solved the problem. The problem is Python version that i used. The problem occur pyton2 versions, but on python3 versions it Works correctly.
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]
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.