views:

682

answers:

4

I know this must be a pretty common problem, but I haven't been able to find a definitive answer on how to do it.

First, assume we have a java server that accepts queries such as (I've just put the relevant lines, and I've taken out the exception handling for clarity):

    ServerSocket socket = new ServerSocket(port);
    while (true) {
        ClientWorker w;
        w = new ClientWorker(socket.accept());
        Thread t = new Thread(w);
        t.start();
    }

and then in the ClientWorker

 BufferedReader inFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
 DataOutputStream outToClient = new DataOutputStream(client.getOutputStream());

 String query = inFromClient.readLine();
    // process query here
 String response = "testresponse";

 outToClient.writeBytes(response + "\n");

 outToClient.close();
 inFromClient.close();
 client.close();

Right now I can get a java client that works with this server:

String query = "testquery";
Socket queryProcessorSocket = new Socket(queryIp,queryPort);
DataOutputStream queryProcessorDos = new DataOutputStream(queryProcessorSocket.getOutputStream());
BufferedReader queryProcessorReader = new BufferedReader(new InputStreamReader(queryProcessorSocket.getInputStream()));
queryProcessorDos.writeBytes(query + "\n");
String response = queryProcessorReader.readLine();

But how can I get a C++ client to do the same thing as the java client? I've tried many things but nothing seems to work. Ideally I wouldn't want to touch the java server, is that possible? If someone could point me to a good example or some sample code, that would be much appreciated. I searched through a lot of websites but to no avail.

+2  A: 

How do you mean "it doesn't work" ?

Without studying the code too carefully, my first concern is that you're converting a String (in chars, or byte-pairs) to bytes, and then sending these down the socket. Are you retrieving these in the same fashion on the C++ end ? i.e. using the same character encoding ?

Brian Agnew
i will complement this answer by saying that Java uses Unicode (UTF-16) to store a character. so either you convert your Java String to ANSI before sending or you use a std::wstring on the C++ client side.
Adrien Plisson
@Adrien - worthwhile points to make
Brian Agnew
A: 

Yes you can have a C++ client (or a C client or a COBOL client or a perl client or a ruby client or a ... client) talk to a java server. All you do is port the java code to the equivalent C++ code (or C code or COBOL code or perl code or ruby code or a ... code). The server neither knows nor cares what language the client is written in.

I would start with this reference Internet Sockets and then use the POSIX API Documentation.

David Harris
+5  A: 

Here I put a simple code to connect to a server. It may help you if this is your problem.

void client(const char* server_address, short server_port)
{
     int     sockfd;
     struct sockaddr_in servaddr;

     sockfd = socket(AF_INET, SOCK_STREAM, 0);

     memset(&servaddr, 0x00, sizeof(servaddr));
     servaddr.sin_family = AF_INET;
     servaddr.sin_port = htons(server_port);
     inet_pton(AF_INET, server_address, &servaddr.sin_addr);

     connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

     //from this point you can start write to the server and wait for its respose

     std::string buffer = "testquery";
     writen(sockfd, buffer.c_str(), buffer.length());

     char *ReadBuffer[512];
     while(1)
     {
         memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
         int n = readn(sockfd, ReadBuffer, sizeof(ReadBuffer));
         if(n <= 0)
         {
             //or you dont have anything to read, or you have a problem
             break;
         }
         //this function does the hard job of knowing what to do with all these data
         processBuffer(ReadBuffer, n);
     }

 close(sockfd);

 }

I'm using Posix standard and the code is very simplified but I think its a start point.

Regards.

Andres
Nice example, although you should really remember to check return codes and especially check error codes. Your loop will end if an error occurs and you don't check to ensure that connect succeeded. In networking code, it is absolutely imperative that you always know how much data is actually in your buffer also, do NOT assume that things are null-terminated. Also, multiple calls to send on one side can result in those buffers being concatenated so that you get all of the data in one read on the other side.
Jeff Tucker
Slight nitpicky points: Kind of weird that you keep writing 512 instead of sizeof(ReadBuffer). Also, what if read() gets EINTR?
asveikau
@Jeff: Actually, from reading the code example I assumed processBuffer() would handle errors and perhaps copy any partially-complete requests split over multiple reads to a separate heap buffer to be processed on the next read. At least, that's what I'd do.
asveikau
Yes, as I said, the code is very, very simplified. Of course it should be improved a lot. I consider it just an example for a start, not a end solution.
Andres
You might want to include the code for `writen()` and `readn()` or mention where they came from (UNIX Network Programming IIRC).
D.Shawley
+1  A: 

As long as your're not using a language specific protocol (such as Java RMI) and using straight sockets (or some other language neutral protocol like web services) then it will work. You just have to make sure your client and server are speaking the same protocol (e.g. TCP/IP + your custom protocol on top). If using straight sockets you're basically sending binary over the wire - so you need to make sure you're encoding/decoding the data the same on both sides. Typically this is done with some sort of byte level protocol if you're rolling your own. As an example Project Dark Star is a game server written in Java but has clients in Java, C/C++, Flash etc. It uses user defined a binary protocol for cross language communications.

Jeremy Raymond