Socket connection between Java and Python - java

I have a simple Java Socket connected to my Python socketserver.
In the client I want to send some data with size given in input: I want first sent an Integer with the size of the data and then the chunk of byte data.
This is the client:
Integer size = 1234
Socket so = new Socket("10.151.0.248", 8000);
byte[] bytes = new byte[size];
DataOutputStream out = new DataOutputStream(so.getOutputStream());
out.writeInt(size);
out.write(bytes);
From the server side I would like to read the amount of data that will arrive first and then read the stream again till everything is received; as final step I will send back an ACK to the client.
Here is the server:
def handle(self):
tot_data = []
length = self.request.recv(4)
size = struct.unpack("!i", length)[0]
while len(tot_data) < size:
data = self.request.recv(size - len(tot_data))
if not data: break
tot_data.append(data)
data = bytes(b"ACK")
# just send back the ack when transfer completed
self.request.sendall(data)
I am able to retrieve the size of the data in the server, but when I try to read the actual data from the stream, just 4 bytes are retrieved again and then the recv() remain blocked waiting for more data. I would like, first, to retrieve all the data, and then send back the ACK once the transfer is completed.
Any suggestions?

There one problem in the handle method Python side. self.request.recv returns a string (for Python 2.x, it will be bytes for Python3), and you assemble strings in an array. So the length of the array is just the number of chunks and not the number of bytes received.
You should write:
def handle(self):
tot_data = b""
length = self.request.recv(4)
size = struct.unpack("!i", length)[0]
while len(tot_data) < size:
data = self.request.recv(size - len(tot_data))
if not data: break
tot_data += data
data = bytes(b"ACK")
# just send back the ack when transfer completed
self.request.sendall(data)

Related

How to receive only actual data from a socket

i am sending 20 bytes of data from my udpserver to a client in java. At the client side i am receiving like this
byte[] buf = new byte[25];
final DatagramPacket recv = new DatagramPacket(buf,25);
String data = new String(recv.getData());
when i print data it is printing additional things. How can i only get my actual data. Please suggest.
You are sending 20 bytes, but you are allocating a receive buffer that can receive up to 25 bytes. The received datagram can be smaller, but you need to take the actual received length into account when constructing the String, eg:
String data = new String(recv.getData(), 0, recv.getLength());

Sending data from a java server in a consecutive way

Here is my java server code:
public class CaspSocket {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
public CaspSocket(InetAddress caspAddress, int caspPort) throws IOException {
socket = new Socket(caspAddress, caspPort);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
I use "out" to send data
out.print(1 + "|");
out.print(2 + "|");
out.print(3 + "|");
It will be received in GameMaker Studio as follows:
var in_buff = ds_map_find_value(async_load, "buffer");
test_string=buffer_read(in_buff, buffer_string);
This way everything will be put into a single string
test_string="1|2|3|"
However I want to receive the data in in a consecutive way
var in_buff = ds_map_find_value(async_load, "buffer");
test_string=buffer_read(in_buff, buffer_string);
test_string2=buffer_read(in_buff, buffer_string);
test_string3=buffer_read(in_buff, buffer_string);
to give
test_string="1|" test_string2="2|" test_string3="3|"
How do I send data from the java server in a consecutive way so that each chunk of data can be read out individually using buffer_read(in_buff, buffer_string); in GameMaker Studio
Edit:
I have read the using buffers section the problem is when I send in GameMaker Studio to the server using this:
buffer_seek(Buffer, buffer_seek_start, 0);
buffer_write(Buffer, buffer_string, string(1) + chr(10)); //chr(10) means new line
buffer_write(Buffer, buffer_string, string(2) + chr(10));
buffer_write(Buffer, buffer_string, string(3) + chr(10));
network_send_raw(Socket, Buffer, buffer_tell(Buffer));
The java server will only send back one string:
var in_buff = ds_map_find_value(async_load, "buffer");
buffer_read(in_buff, buffer_string);
I don't know how this should be send sequentially using the java server, like it can be received in GM:S:
var in_buff = ds_map_find_value(async_load, "buffer");
test_string=buffer_read(in_buff, buffer_string);
test_string2=buffer_read(in_buff, buffer_string);
test_string3=buffer_read(in_buff, buffer_string);
I will only be using buffer_string to make things easier.
The socket communication is based on the concept of streams. Streams are plain sequence of bytes and there is no way how you can control how they are sent. The actual transport is managed by the OS protocol driver and is not accessible from applicatio level. So based on the multiple conditions
out.print(1 + "|");
// some other code
out.print(2 + "|");
// some other code
out.print(3 + "|");
may be delivered in a single packet or several packets. Even flush() method will just push data to OS buffer and guarantee you nothing about the actual delivery.
So to read messages sequentially you should ether
Know their sizes and read into buffers of expected size (you may send some kind of "header" of fixed size data first which will tell the size of the "body" data next, then next "header" and so on)
Read full available content and split it in your client app using data delimeters (it your case this seem to be | character)

Sending 1 MB Buffer of data over Socket in Android

How can i send a buffer of data whose length is 1 MB over socket in java.
What exactly i am doing is that i want to calculate upload speed of network.For that i want to send 1 MB data to server which i have written in C.
In C to receive and send data we have functions like send and recv through which we can send the desired number of bytes by passing the number of bytes to be sent.
send(connfd , client_message , `Bytes to send`, 0);
but in java i am able to send only 1 byte at a time using
int buffer[] = new int[1048576];
PrintWriter output1 = new PrintWriter(socket.getOutputStream(), true);
output1.print(buffer[1]);
so to send multiple bytes i need to call above function again and again. Is there any way in which i can pass whole buffer of 1048576 in on go.
Your PrintWriter has a print(char[] s) method (see doc). So you could instead create a new char array with the corresponding size (note: a char in Java is 2 byte long) and send that char array using that method.
But there is a better option: A look into the doc tells us we get an OutputStream from our socket. We could wrap that into a BufferedOutputStream, like this:
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte buffer[] = new byte[1024*1024];
bos.write(buffer, 0, buffer.length);
And then use bos.write(byte[], int, int) to directly send a byte array, which probably would be the most direct way to achieve what you want.

Transferring Data Between Client and Server and Dynamically Flush

I've been playing around with transferring data between a test client (written in Java) and a server (written in C#/.NET).
I tried TCP clients and servers, but there has been and current is a problem flushing the stream. I realize flush doesn't always flush the stream, so I'm wondering if there is any way to flush/send a stream without .flush() or in a more reliable way?
Currently, the important part of the client looks like this (message is a string, serverSocket is a Socket object):
OutputStream output = serverSocket.getOutputStream();
byte[] buffer = message.getBytes();
int length = buffer.length;
output.write(ByteBuffer.allocate(4).putInt(length).array());
output.write(buffer);
output.flush();
and the server looks like this:
NetworkStream stream = client.GetStream ();
byte[] sizeBuffer = new byte[4];
int read = stream.Read (sizeBuffer, 0, 4);
int size = BitConverter.ToInt32 (sizeBuffer, 0);
Databaser.log ("recieved byte message denoting size: " + size);
byte[] messageBuffer = new byte[size];
read = stream.Read (messageBuffer, 0, size);
string result = BitConverter.ToString (messageBuffer);
Databaser.log ("\tmessage is as follows: '" + result + "'");
Where, if it's not evident from the code, the client sends 4 bytes, which are combined into a 32 bit integer which is the length of the message. Then I read in the message based on that length and have build in converters translate it into a string.
As I said, I'm wondering how to flush the connection? I know this code isn't perfect, but I can change it back to when I used TCP and UTF exclusive string messaging over the network, but either way, the connection doesn't send anything from the client until the client shuts down or closes the connection.
Maybe the problem is in the byte order. I have an application which send from a tablet (java) to a C# application (Windows Intel), I used similar to what you've done, except in the following
ByteBuffer iLength = ByteBuffer.allocate(4);
iLength.order(ByteOrder.LITTLE_ENDIAN);
iLength.putInt(length);
output.write(iLength.array(), 0, 4);
output.write(buffer);
output.flush();
Java uses BIG-ENDIAN and Intel uses LITTLE-ENDIAN bytes order.

Failed to convert data from UDP packet into the initial data which is sent using Java

I'm writing a UDP Client to transfer a file to a UDP server. First I try to measure the length of the file, devided by the buffer length to be sent in UDP packet, to get the number of packets required to be sent. I send this number to the server first to acknowledge it. But on the server side, the transform from byte array of the receiving packet into the initial number just failed. Can anyone help me out of this? Here is my code on the client side:
DatagramSocket socket=new DatagramSocket();
File f = new File(filename);
long fileSize = f.length();
byte[] buffer = new byte[16384];
long packetNumber = (fileSize/(buffer.length))+1;
DatagramPacket sendPacket=new DatagramPacket(buffer,buffer.length,addr,srvPort);
String str=Long.toString(packetNumber);
buffer = str.getBytes();
socket.send(sendPacket);
And here is the code on the server side:
DatagramSocket socket=new DatagramSocket(port);
byte[] buffer=new byte[16384];
DatagramPacket receivePacket=new DatagramPacket(buffer, buffer.length);
while(true)
{
socket.receive(receivePacket);
if (receivePacket.getData().toString().trim()!=null)
{
String str=receivePacket.getData().toString();
System.out.println(str);
long pcount=Long.parseLong(str);
System.out.println(pcount+" packets to be received.");
break;
}
}
But on the server side the variable pcount can always not be resolved, and when I try to print out the str, it writes out some "[B#60991f" or sth, weird.
This code doesn't make any sense.
Most networks won't let you send a datagram over 534 bytes reliably.
At present you are sending 16384 bytes of zero value, because you aren't putting anything into the buffer: instead you are creating a new buffer after creating the DatagramPacket. So you aren't sending anything yet.
And you aren't receiving anything yet either. The result of String.trim() cannot be null. You must reset the byte array in a DatagramPacket before every receive(), because it shrinks to the size of the actual received packet, so unless you reset it it keeps getting smaller and smaller. The result of toString() on a byte array does not include its contents, so parsing it is futile.
You need to study several basic Java programming concepts: too many to answer here.
You're receiving a byte array, using toString() won't give you anything.
You should reconstruct the String from the bytes array using new String

Categories