I am trying to set up a simple Boost ASIO server with a single Java client.
I am able to send and successfully receive strings between the two. However, when I try to send double values, only garbage comes out on the other end.
Below is stand alone code that shows my basic setup (with a C++ Boost ASIO server and a Java client). When they are run, they do the following four sequential tasks:
The client sends a string to the server, which is successfully received and printed out.
The server sends a string to the client, which is successfully received and printed out.
The client sends a double value to the server, which is received but does NOT print out
correctly.
The server sends a double value to the client, which is received but does NOT print out
correctly.
Does anyone know what I am doing wrong? I am admittedly very new to networking (and Java). I have been through the Boost ASIO documentation and examples but to know avail.
C++ Boost ASIO server code:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/array.hpp>
using boost::asio::ip::tcp;
int main()
{
unsigned short const PORT = 19876;
try
{
boost::asio::io_service ioService;
tcp::acceptor acceptor(ioService, tcp::endpoint(tcp::v4(), PORT));
while (true)
{
// Listen for clients
std::cout << "Listening for client..." << std::endl;
tcp::socket socket(ioService);
acceptor.accept(socket);
std::cout << "Client heard..." << std::endl;
size_t len;
// Receive string from client and print it out
boost::array<char, 128> cBuf;
len = socket.read_some(boost::asio::buffer(cBuf, sizeof(cBuf)));
std::cout.write(cBuf.data(), len);
// Send string to client
std::string message = "Server string to send to client\n";
boost::asio::write(socket, boost::asio::buffer(message));
// Receive double from client and print it out
double dVal1 = -1.0;
char * p_dVal1 = reinterpret_cast<char *>(&dVal1);
len = socket.read_some(boost::asio::buffer(p_dVal1, sizeof(double)));
std::cout << dVal1<< std::endl; // prints out garbage
// Send double to client
double dVal2 = 6.28;
char const * p_dVal2 = reinterpret_cast<char const *>(&dVal2);
boost::asio::write(socket, boost::asio::buffer(p_dVal2, sizeof(double)));
}
}
catch (std::exception & e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
Java client code:
import java.io.*;
import java.net.*;
public class Client
{
final static String HOST = "localhost";
final static int PORT = 19876;
public static void main(String[] args) throws IOException
{
Socket socket = new Socket(HOST, PORT);
// Send string to server
PrintWriter pos = new PrintWriter(socket.getOutputStream(), true);
pos.println("Client string to send to server");
// Receive string from server
BufferedReader bis =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(bis.readLine());
// Send double value to server
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeDouble(3.14);
// Receive double from server
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println(dis.readDouble()); // prints out garbage
socket.close();
pos.close();
bis.close();
dos.close();
dis.close();
}
}
Thank you very much in advance!!!
Aaron
You need to use a lexical_cast, not a reinterpret_cast.
With reinterpret_cast, you're telling the compiler to literally interpret the double* bit pattern as a const char* bit pattern. Instead, your cast should create a new structure with ascii chars that represent the number in an ascii bit pattern.
Also, you should ensure that you're managing endianess. You should properly convert to and from network endianess on both the client and server. See this answer for additional information.
Related
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.
I have a Java TCP Server Socket program that is expecting about 64 bytes of data from a piece of remote hardware. The Server code is:
public void run () throws Exception
{
//Open a socket on localhost at port 11111
ServerSocket welcomeSocket = new ServerSocket(11111);
while(true) {
//Open and Accept on Socket
Socket connectionSocket = welcomeSocket.accept();
DataInputStream dIn = new DataInputStream(connectionSocket.getInputStream());
int msgLen = dIn.readInt();
System.out.println("RX Reported Length: "+ msgLen);
byte[] msg = new byte[msgLen];
if(msgLen > 0 ) {
dIn.readFully(msg);
System.out.println("Message Length: "+ msg.length);
System.out.println("Recv[HEX]: " + StringTools.toHexString(msg));
}
}
}
This works correctly as I am able to test locally with a simple ACK program:
public class ACK_TEST {
public static void main (String[] args)
{
System.out.println("Byte Sender Running");
try
{
ACK_TEST obj = new ACK_TEST ();
obj.run();
}
catch (Exception e)
{
e.printStackTrace ();
}
}
public void run () throws Exception
{
Socket clientSocket = new Socket("localhost", 11111);
DataOutputStream dOut = new DataOutputStream(clientSocket.getOutputStream());
byte rtn[] = null;
rtn = new byte[1];
rtn[0] = 0x06; // ACK
dOut.writeInt(rtn.length); // write length of the message
dOut.write(rtn); // write the message
System.out.println("Byte Sent");
clientSocket.close();
}
}
And this correctly produces this output from the Server side:
However, when I deploy the same Server code on the Raspberry Pi and the hardware sends data to it, the data length is far greater and causes a heap memory issue (Even with the Heap pre-set at 512MB, which is definitely incorrect and unnecessary)
My presumption is I am reading the data wrong from the TCP socket as from the debug from the hardware, it's certainly not sending packets of this size.
Update: I have no access to the Client source code. I do however need to take the input TCP data stream, place it into a byte array, and then another function (Not shown) parses out some known HEX codes. That function expects a byte array input.
Update: I reviewed the packet documentation. It is a 10 byte header. The first Byte is a protocol identifier. The next 2 bytes is the Packet Length (Total number of bytes in the packet, including all the header bytes and checksum) and the last 7 are a Unique ID. Therefore, I need to read those 2 bytes and create a byte array that size.
Apparently the length from the header is about 1GB. Looks like the problem on the other end. Don't you mix low/big endian encoding?
I am currently trying to send strings via sockets between Java and c. I am able to either send a String to the client (c) from the server (java), or vice versa, but not BOTH, which is how I need to communicate between the two. In my c (client) code, as soon as I insert the read portion, the code haults.
Here are my two portions of code. It is safe to assume the connection between the sockets is successful.
java:
private void handshake(Socket s) throws IOException{
this.out = new PrintStream(s.getOutputStream(), true);
this.in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String key = in.readLine(); //get key from client
if(!key.equals(CLIENTKEY)){
System.out.println("Received incorrect client key: " + key);
return;
}
System.out.println("received: " + key);
System.out.println("sending key");
out.println("serverKEY"); //send key to client
System.out.println("sent");
}
c:
int n;
n = write(sockfd,"clientKEY",9);
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
n = read( sockfd,recvBuff,255 );
if (n < 0)
{
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %s\n",recvBuff);
Modify your C send code:
char clientKey[] = "clientKEY\n"
n = write(sockfd,clientKey, strlen(clientKey));
It's better to use a variable for clientKey and then call strlen so you don't have to count char's manually. As Jiri pointed out, Java's readLine function is probably expecting a newline char that it's never getting so it hangs.
It seems to me that the C/C++ server sends a clientKEY message to the Java client. The Java client reads a line, i.e. waits till it receives the \n character from the C/C++ server. However, it is never sent by the C/C++ server and so the Java client waits... forever.
I have a C++ server and two clients (ruby and java).
Everything is running on a 64-bit linux-machine (java 1.7.0_17)
The ruby client is fully working, but the java version makes problems.
In Java I tried to send a String from the client to the server. Actually the Server received the entire String, but the server thinks there is still something more to receive.
The ruby client looks a little bit like this:
socket = TCPSocket.open(#options[:host],#options[:port])
test = "Hello, World"
socket.puts test
socket.shutdown 1
response = socket.gets
Everything here is working fine. The ruby client sends a string. The server receives that string and sends a reply.
The Java Version looks like:
String ip = "127.0.0.1";
int port = 6686;
java.net.Socket socket = new java.net.Socket(ip,port);
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
InputStreamReader in = new InputStreamReader(socket.getInputStream());
String msg = "Hello, world!";
//send
PrintWriter pw = new PrintWriter(out, true);
pw.print(msg);
pw.flush();
// I also tried: out.write(msg); out.flush(); nothing changed
//receive the reply
BufferedReader br = new BufferedReader(in);
char[] buffer = new char[300];
int count = br.read(buffer, 0, 300);
String reply = new String(buffer, 0, count);
System.out.println(reply);
socket.close();
On the other side there is a C++ Server:
string receive(int SocketFD) {
char buffer[SOCKET_BUFFER_SIZE];
int recv_count;
// empty messagestring
string message = "";
// empty buffer
memset(buffer, 0, sizeof(buffer));
while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) {
/*if (recv_count == -1) {
cout << "failed." << endl;
break;
}*/
cout << recv_count << endl;
if (ECHO_SOCKETS) cout << "received: " << buffer << endl;
message.append(buffer);
memset(buffer, 0, sizeof(buffer));
if (ECHO_SOCKETS) cout << "message is now: " << message << endl;
}
return message;
}
The server output from the Java-message is:
13
received: Hello, world!
message is now: Hello, world!
and then nothing happens.
The problem is that:
recv(SocketFD, buffer, sizeof(buffer) - 1, 0)
is catched in an endless loop (or something like that).
If I kill the Java-client process or I type something like:
pw.print(msg);
out.close();
the output on the server side is:
_sending reply: "Request unrecognized/invalid" request="Hello, world!"
send reply success
now close connection
This output is right (except "send reply success"), but in case of adding:
out.close();
the client can't receive the reply of the server. Because the Socket is closed.
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Socket.java:864)
at MyServer.writeMessage(MyServer.java:56)
at MyServer.test(MyServer.java:42)
at MyServer.main(MyServer.java:30)
Edit
I tried to call pw.flush(); and different delimiters like "\n", "\r", "\r\n" and "\n\r" but the server still thinks there is still something to read. I also tried to use DatagramSockets:
java.net.DatagramSocket dSocket = new java.net.DatagramSocket();
InetAddress address = InetAddress.getByName("localhost");
String msg = "Hello, world!";
byte[] buf = msg.getBytes();
java.net.DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 6686);
But the server can't accept the packet.
Solution
The ruby-client does something like a socket.shutdownOutput(); (ruby: socket.shutdown 1) after the call of puts. I changed the java-client-code:
out.write(msg);
socket.shutdownOutput();
and it works!
As #Charly said: I have to define a "protocol". In my case I'm not allowed to change any communication related code (in the server and the ruby-client) because this functionality is used by a another group of researchers. So I've to modify my java-client in that way, that it does the exact same things at the exact same time as the ruby-client (something like a protocol).
PrintWriter buffer (when autoflush is true) is only flushed by calling println or printf. Calling print may not flush the buffer (Javadoc). Try calling println or use a OutputStreamWriter directly and flush().
Be aware of using the right charset (You can set it up in OutputStreamWriter constructor).
Close the stream respectively flush it in a way like this:
DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
dataOut.writeUTF(s);
dataOut.flush();
while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) {
if (recv_count == -1) {
I don't know what your problem is but this code is certainly nonsense. It is impossible for the inner test ever to succeed.
I'm starting to write my first Java networking program, and long story short I'm having difficulty making sure that I'm taking the right approach. Our professor has given us a server program to test against this UDP client, but I'm getting some errors I can't seem to squash. Specifically, I get IO exceptions, either "Connection Refused" or "No route to host" exceptions.
public class Lab2Client {
/**
* #param args[1] == server name, args[2] == server port, args[3] == myport
*/
public static void main(String[] args) {
//Serverport is set to 10085, our client is 10086
try {
Socket echoSocket = new Socket(args[0],Integer.parseInt(args[2]));
System.out.println("Server connection Completed\n");
DataOutputStream output = new DataOutputStream(echoSocket.getOutputStream());
byte[] toSend = new byte[5];
toSend[0] = 12; toSend[1] = 34;//Code Number
toSend[2] = 15;//GroupId
toSend[3] = 86;toSend[4] = 100;//Port number in Little Endian Order
output.write(toSend);
System.out.println("Sent Request. Waiting for reply...\n");
DataInputStream input = new DataInputStream(echoSocket.getInputStream());
byte[] toRecieve = new byte[]{0,0,0,0,0,0,0,0};
input.read(toRecieve);
checkMessage(toRecieve);
}
catch (UnknownHostException e) {
System.err.println("Servername Incorrect!");
System.exit(1);
}
catch (IOException e){
System.err.println("IO Exception. Exiting...");
System.err.println(e);
System.exit(1);
}
}
I also have some questions about my implementation regarding receiving messages in Java. I'll be getting a datagram that contains either:
a) 3 formatting bytes (unimportant to the question) along with an IP and port number
or
b) 3 formatting bytes and a port.
Is using a DataInputStream the correct way to do this? I know using an array with 9 elements is lazy instead of dynamically allocating one that's either 5 or 9, but right now I'm just trying to get this working. That being said, is there a different approach anyone would suggest for this?
You need not to wrap the stream returned by Socket.getOuputStream() with DataOutputStream - it is already the DataOutputStream
In this line:
Socket echoSocket = new Socket(args[0],Integer.parseInt(args[2]));
I suppose it should be args[1], not args[0].
Here you have to convert the integer value to its byte representation:
toSend[3] = 10086 & 0xFF;toSend[4] = 10086>>8; //Port number in Little Endian Order
Answer to your question: case b as you are not sending the IP
thought I'd leave this up for posterity. The problem is simple, and I'm a fool for not noticing it sooner.
The correct programs I was testing this against used the UDP protocol, and this program is written in TCP. The corrected code is:
public class Lab2Client {
/**
* #param args[0] == server name, args[1] == server port, args[2] == myport
*/
public static void main(String[] args) {
//Serverport is 10085, our client is 10086
try {
DatagramSocket clientSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName(args[0]);
int portToSend = Integer.parseInt(args[2]);
System.out.println("Clent Socket Created");
byte[] toSend = new byte[5];
toSend[0] = 0x12; toSend[1] = 0x34;//Code Number
toSend[2] = 15;//GroupId, f in hex
toSend[3] = 0x27;toSend[4] = 0x66;
System.out.println("Byte Array Constructed");
DatagramPacket sendPacket = new DatagramPacket(toSend, toSend.length, IPAddress, Integer.parseInt(args[1]));
clientSocket.send(sendPacket);
System.out.println("Sent Request. Waiting for reply...\n");
DataInputStream input = new DataInputStream(echoSocket.getInputStream());
toRecieve can either be an error message, a return of what we sent,
or a byte stream full of IP info and port numbers.
the "heavy" byte stream is either 4 for IPv4 of 16 for IPv6, 2 bytes for port,
and the magic number (2 bytes) for a total of 9-20 bytes*/
byte[] toRecieve = new byte[9];
DatagramPacket receivePacket = new DatagramPacket(toRecieve, toRecieve.length);
clientSocket.receive(receivePacket);
checkMessage(toRecieve);
} //and so on and so forth...
Thanks to #Serge for the help, though nobody could have answered my question correctly with how I asked it. The byte shifting you suggested was important too.