I'm creating a server app in C++ and client app in Java. I want to exchange 32 bit integer between them.
And I've got a trouble, because when I'm trying send something from Java's client, I get a random answer in C++ server (e.g. I've send '0' and one time I've got a one number, another time I've got different number. I've read about Little and Big Endian coding, but I think it is another issue, because sending '0' generate a huge value different from 0.
Java Client:
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Main {
public static void main(String[] args) throws Exception{
Socket socket = new
Socket(InetAddress.getByName("127.0.0.1"),10000);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeInt(0);
}
}
C++ Server:
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
#include <iostream>
using namespace std;
int main(){
int port = 10000;
string ip_addr = "127.0.0.1";
int domain = AF_INET;
int type = SOCK_STREAM;
int protocol = 0;
int stopCondition = 0xFFFFFFFF;
int socketHandle;
struct sockaddr_in address;
int clientSocketHandle;
struct sockaddr_in clientAddress;
size_t clientAddressSize;
int buffer;
if((socketHandle=socket(domain,type,protocol))<0)
cout<<strerror(errno);
address.sin_family = domain;
inet_pton(domain,ip_addr.c_str(),&address.sin_addr);
address.sin_port=htons(port);
if((bind(socketHandle,(struct sockaddr *)&address,sizeof(address)))<0)
cout<<strerror(errno);
if (listen(socketHandle, 1) < 0)
cout << strerror(errno);
if ((clientSocketHandle = accept(socketHandle, (struct sockaddr *) &clientAddress, (socklen_t *) &clientAddressSize)) < 0)
cout << strerror(errno);
do {
if (recv(clientSocketHandle, &buffer, sizeof(int), 0) > 0)
cout<<buffer<<endl;
} while (buffer != stopCondition);
if(shutdown(clientSocketHandle,SHUT_RDWR)<0)
cout<<strerror(errno);
if(shutdown(socketHandle,SHUT_RDWR)<0)
cout<<strerror(errno);
return 0;
}
How should I implement my client in Java to work properly with my C++ server?
Related
I'm experiencing some issues while trying to connect BSD client socket to the server.
Socket creation and connecting are implemented with JNI. The actual connection is established via java code.
JNI part:
#include <jni.h>
#include <unistd.h>
#include <string.h>
#include <sys/endian.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
JNIEXPORT jint JNICALL Java_com_example_socketclinet_Native_socket
(JNIEnv *, jclass, jint, jint, jint);
JNIEXPORT jint JNICALL Java_com_example_socketclinet_Native_connect
(JNIEnv *, jclass, jint, jint, jint);
jint JNICALL Java_com_example_socketclinet_Native_socket
(JNIEnv *env, jclass cls, jint domain, jint type, jint protocol)
{
return socket(domain, type, protocol);
}
jint JNICALL Java_com_example_socketclinet_Native_connect
(JNIEnv *env, jclass cls, jint socket, jint address, jint port)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(address);
addr.sin_port = htons(port);
return connect(socket, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in));
}
Java native-bridge class:
class Native
{
static
{
System.loadLibrary("mylib");
}
public static final int SOCK_STREAM = 2;
public static final int AF_INET = 2;
public static native int socket(int domain, int type, int protocol);
public static native int connect(int socket, int address, int port);
}
Native class usage:
int socket = Native.socket(Native.AF_INET, Native.SOCK_STREAM, 0);
if (socket < 0)
{
System.err.println("Socket error: " + socket);
return;
}
byte[] address = { .... }; // 192.168.xxx.xxx
int addr = address[0] << 24 | address[1] << 16 | address[2] << 8 | address[3];
int port = ....;
int result = Native.connect(socket, addr, port);
if (result < 0)
{
System.err.println("Connection failed: " + result);
}
else
{
System.out.println("Connected");
}
The "connect" method always returns "0" even if there's no server running (both on device and simulator).
• I have "INTERNET" permission set with the manifest file (without it "socket" function returns -1)
• The same code works perfectly fine on iOS and Mac OS.
• Testing environment: Nexus 5 (4.4.4), android-ndk-r10d
Any help will greatly appreciated!
byte[] is signed in Java, which means your |addr| computation is likely wrong. I suspect you are connecting to a broadcast address, which will always succeed by definition.
Try printing the address from native code through to verify that, otherwise, try to replace the computation with:
int addr = (address[0] & 255) << 24 |
(address[1] & 255) << 16 |
(address[2] & 255) << 8 |
(address[3] & 255);
To see if that solves the problem.
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.
I have a simple server written in Java, that just sends an Integer to a connected client. I have a client written in C, that connects to the server and prints out the received Integer.
My problem is that the result varies. About half of the times executing the client I get the correct result (234), but other times I get 8323072.
This is the server:
class TCPServer {
public static void main(String args[]) throws Exception {
ServerSocket welcomeSocket = new ServerSocket(6789);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
System.out.println("welcomeSocket.accept() called");
DataInputStream inFromClient = new DataInputStream(connectionSocket.getInputStream());
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
outToClient.writeInt(234);
}
}
}
And this is the client:
int main(int argc, char *argv[])
{
if(argc != 4){
printUsage();
return;
}
char* serverIP = argv[1];
char* serverPortC = argv[2];
char* integerToSendC = argv[3];
int serverPort = atoi(serverPortC);
int integerToSend = atoi(integerToSendC);
int socketDesc = socket(AF_INET, SOCK_STREAM, 0);
if(socketDesc < 0) {
printf("Error when creating socket\n");
return;
}
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(serverPort);
inet_pton(AF_INET, serverIP, &serverAddr.sin_addr);
int connection = connect(socketDesc, (struct sockaddr*) &serverAddr, sizeof serverAddr);
if(connection < 0) {
printf("Error when establishing connection\n");
return;
}
char intBuffer[4];
if(recv(socketDesc, intBuffer, sizeof intBuffer, 0) == -1){
printf("Error while receiving Integer\n");
}
int receivedInt = ntohl(*((int *) &intBuffer));
printf("Received int: %d\n", receivedInt);
close(socketDesc);
}
Thanks in advance for any help!
Edit:
So in the end I did something like this, just for anybody who has the same problem:
while(receivedBytes < 4){
int readBytes = read(receiverSocket, &intBuffer, (sizeof intBuffer) - receivedBytes, receivedBytes);
receivedInteger += (intBuffer << (8*receivedBytes));
receivedBytes += readBytes;
}
Can you be sure you have received sizeof intBuffer bytes on the client side? No you can not, as recv() might return less bytes then requested.
Mod you code to loop around recv() as long as less bytes then requested have been received and no error occurred.
Note that recv()ing 0 bytes indicates the connection had been closed by the other side.
Also make sure the server side sends in network byte order.
Also^2: It is good idea to initialise variables (intBuffer here), at least during the development phase, will say: prior to the tuning phase.
Your problem could be because of the sub-boundaries of the various data types.
In Java, 4 bytes are assigned to int and 2 bytes for a short.
In C, 4 bytes are for long and 2 bytes for int.
This means Java int -> C long and Java short -> C int.
Now it depends on where your priorities lie.
If you want to perform an intense mathematical calculation in Java and send the result over socket to C, I recommend you do Java int -> C long or
If you want to just send small numbers and have the intense calculation done in C, do the Java short -> C int conversion.
Hope that helped.
This question may sound basic one . Are there any functions in c or Java where I can get the socket details like , port , address , buffer size using only socket identifier ?
Some minimal information available with me is posted below.
I don't know much of Java. But as far as 'C' is concerned, you can use the getsockopt function to get the buffer sizes (send buffer and recv buffer) of the socket.
It appears getsockname helps you in getting the ip & port to which the socket is bound to.
In c in the function accept:
csock = accept(sock, (struct sockaddr*)&csin, &recsize);
sock is the socket server(int)
csock is the socket client (int)
recsize is the size
csin is a struct with client's details
csin.sin_addr is the client's address
csin.sin_port is the client's port
From a socket ID try this:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
f()
{
int s;
struct sockaddr_in sa;
int sa_len;
.
.
.
/* We must put the length in a variable. */
sa_len = sizeof(sa);
/* Ask getsockname to fill in this socket's local */
/* address. */
if (getsockname(s, &sa, &sa_len) == -1) {
perror("getsockname() failed");
return -1;
}
/* Print it. The IP address is often zero beacuase */
/* sockets are seldom bound to a specific local */
/* interface. */
printf("Local IP address is: %s\n", inet_ntoa(sa.sin_add r));
printf("Local port is: %d\n", (int) ntohs(sa.sin_port));
.
.
.
}
Hey guys, i've been searching for some info on sockets programming for a few hours right now and still can't understand how to solve a problem i have.
I've been asked to do the following :
The server receives an UDP datagram at the port 8080, sent from a client, in the datagram the client sends an array of chars that represents a number(9090)
The server will create a new socket, establish a TCP connection with the client at the port
9090.
Through the tcp connection, the server will read the a name, sent by the client.
We're asked to write a client able to do those tasks in C, the server is already done and is found in a .jar file
The program should run like this : ./client SERVER_NAME
and the server: java -jar server.jar
i got as far as this goes...with a think it covers the first part(sending the udp package) but not quite sure how to follow:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "8080" // the port users will be connecting to
int main(int argc, char *argv[])
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
if (argc != 2) {
fprintf(stderr,"usage: talker hostname\n");
exit(1);
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
int num = 9090;
num = htonl(num);
if ((numbytes = sendto(sockfd, num, sizeof(num), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto");
exit(1);
}
Does the java server provide any feedback you can use to verify the your UDP thus far? If so, I would verify and proceed as follows..
Setup a separate socket to make the TCP connection. There are many resources on the Internet showing how to do that (Google 'c tcp client example'). Since UDP is an unreliable best-effort protocol you will want to have a method for retrying the connection. One solution might be to loop, sending the UDP datagram and trying the TCP connection on the other socket until the connection is made (or some other time limit or maximum retry limit is reached).
// setup TCP socket to connect to your chosen port 'num'...
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
// handle error
struct sockaddr_in tcpServAddr;
memset(&tcpServAddr, 0, sizeof(tcpServAddr));
tcpServAddr.sin_family = AF_INET;
tcpServAddr.sin_addr.s_addr = inet_addr(<insert server ip here>);
tcpServAddr.sin_port = htons(num);
const int iMaxTries = 10;
int iTryCount = 0;
bool bConnected = false;
while(!bConnected && (iTryCount < iMaxTries)) {
// using your bock from above:
if ((numbytes = sendto(sockfd, num, sizeof(num), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto"); // may want to output strerr(errno) for more information
break; // something is wrong if we can't send UDP. bail and figure that out
}
++iTryCount;
// try the TCP connection on the target port
if (connect(tcpSockFd, (struct sockaddr *) &tcpServAddr, sizeof(tcpServAddr)) == 0) {
bConnected = true;
} else {
// report error
}
}
if (bConnected) {
// send(...) name on tcpSockFd
}
// cleanup sockets
None of the above is tested, but hopefully it gives you some general direction.