Sending TCP Data between C++ and Java
Ok, Let's say I have a C++ client, and a Java server communicating through a socket over TCP. On the C++ side I cast a struct pointer to a char *: ... struct eventStruct { u_short eventType; char[] userid; }; eventStruct clientSideEvent; clientSideEvent.eventType = 1; clientSideEvent.userid = "simter"; send ( socket, (char *)&clientSideEvent, ...); ... I know in C++ you can just cast the data pointer back into a struct pointer once the data is received at the server: ... eventStruct serverSideEvent; recv( socket, (char *)&serverSideEvent, ...); ... Is there a way to do the receive in Java that is just as neat and tidy? Thanks, Stip
Quote:
Original post by stipperdoo
Ok,
Let's say I have a C++ client, and a Java server communicating through a socket over TCP. On the C++ side I cast a struct pointer to a char *:
...
struct eventStruct {
u_short eventType;
char[] userid;
};
eventStruct clientSideEvent;
clientSideEvent.eventType = 1;
clientSideEvent.userid = "simter";
send ( socket, (char *)&clientSideEvent, ...);
...
I know in C++ you can just cast the data pointer back into a struct pointer once the data is received at the server:
...
eventStruct serverSideEvent;
recv( socket, (char *)&serverSideEvent, ...);
...
Is there a way to do the receive in Java that is just as neat and tidy?
Thanks,
Stip
Sending the address of an object they way you posted won't work, even in C++.
You need to pass the actual data. You can't pass pointers. You can't pass classes with a vtable because a vtable contains pointers. You will need to transmit some meta-information, such as the type and size of the data you are sending, and include at least some basic serialization code. You can't use a single recv as you posted because packets tend to get broken up. One send can be split across multiple recvs, and mupltiple sends might come in a single recv.
You will need to also have some pretty good serialization code to match the native c++ format with the network ordering that Java uses.
Robust networking is not trivial. The FAQ lists some web sites and has some code samples that you should read. Al Steven's books are a must-read, even though they are focused on the Unix environments. You will need to read other books or sources on network programming for the platform your c++ client will run on.
frob.
Interesting. I derived my example from code examples posted in the following thread:
http://www.gamedev.net/community/forums/topic.asp?topic_id=333893
It makes some sense to me. Take the following line of code:
send( socket, (char *)&msgStruct, sizeof(msgStruct), 0 );
Since the send function takes a char pointer, you can send the address of a struct and cast it to a char pointer.
Thanks for the advice. I thought if the information were small enough there would be no danger of it being broken into separate packets.
I have created a successful example of sending short strings between a C++ client and a Java Server located on the same machine. I was mainly concerned with the Java side where a string string is received. Will I have to extract the data manually by reading an integer, then a string, then another string, etc., or is there a way to cast it like in C++?
...Stip
http://www.gamedev.net/community/forums/topic.asp?topic_id=333893
It makes some sense to me. Take the following line of code:
send( socket, (char *)&msgStruct, sizeof(msgStruct), 0 );
Since the send function takes a char pointer, you can send the address of a struct and cast it to a char pointer.
Thanks for the advice. I thought if the information were small enough there would be no danger of it being broken into separate packets.
I have created a successful example of sending short strings between a C++ client and a Java Server located on the same machine. I was mainly concerned with the Java side where a string string is received. Will I have to extract the data manually by reading an integer, then a string, then another string, etc., or is there a way to cast it like in C++?
...Stip
Quote:
Original post by frob
You need to pass the actual data. You can't pass pointers.
He isn't sending the pointer - he's treating the struct pointer as a pointer to an array of characters and effectively sending the bytes of the struct object. So if sizeof(myStruct) is 128 bytes, then he will be sending a character buffer 128 bytes long. This is not an uncommon technique. The RakNet library had this functionality in the past (but I believe I read recently that it is being/has been removed from the library).
Quote:
Original post by stipperdoo
Is there a way to do the receive in Java that is just as neat and tidy?
No, there isn't. You have to extract the fields one at a time. Also, keep in mind that unless your struct is aligned on a particular byte boundary (configurable usually through the command line, pragma/attribute in code, or IDE settings), the compiler will pad it with extra bytes in order to align it. This means that the Java side will be receiving garbage from the padded bytes somewhere in the struct. And even if the server were C++, if it were compiled with a different compiler or with different settings for struct alignment, attempting to cast from the char buffer back into a struct could cause unexpected results.
Also, you can't have any dynamically allocated fields in your structures when using this method. Casting the struct to a char buffer will send the struct data fine. But what is the receiver to do with the memory addresses of any pointers in the struct? The data they point to is on the sender's machine. The data on the receiver's box at that memory address will be something completely different. Now you have a security vulnerability.
When using this casting method, you ought to set your compiler to align your structs on 1 byte boundaries and you must avoid pointers in the structs you use as packets at all costs. Really though, because of the potential for problems it's best to avoid this method altogether and read/write one field at a time. writing individual fields allows you to send them in a specific order, compress them (32-bit boolean values could be sent as 1 byte, for example) or do what ever you want. More importantly, it's safer.
Also keep in mind that any unsigned types you send from the C side will be converted to sign types when you read them on the Java side. For example, if you send a 32-bit unsigned int and want to make sure it remains unsigned, you will most likely need to promote it to a long in Java (long val = byteBuffer.getInt() & 0xFFFFFFFF).
--- Official D Blog | Learning D | The One With D | D Bits
This is why people develop protocols to transmit their data.
This is a little sloppy, obviously, but if you design a clean protocol and create objects that support easy serialization, it isn't bad. (Sorry about the "PLUS" in the last line, but it wasn't showing up as a plus sign for whatever reason).
struct PacketHeader{ uint8_t packetType; uint8_t packetLength;};struct SomeObjectPacket{ PacketHeader header; int objectData1; float objectPosition[3]; ...etc...};// Send and receive this way (pseudocode)SomeObjectPacket packet;packet.header.packetType = SOME_OBJECT_PACKET;packet.header.packetLength = sizeof(SomeObjectPacket);//set data...socket.write(&packet, packet.header.packetLength);// Read it...unsigned char buffer[BUFFER_SIZE];socket.read(buffer, sizeof(PacketHeader));int bytesToRead = ((PacketHeader*)buffer)->packetLength - sizeof(PacketHeader);socket.read(buffer PLUS sizeof(PacketHeader), bytesToRead);//extract the data
This is a little sloppy, obviously, but if you design a clean protocol and create objects that support easy serialization, it isn't bad. (Sorry about the "PLUS" in the last line, but it wasn't showing up as a plus sign for whatever reason).
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement