I would like to make a chat application. The client will be written with java and the server will be written with C. On the server side, the message will be sent as struct. On the client side, how do I read and separate the message with Java?
Here is a sample packet structure:
struct s_packet{
int text_color;
char text[TEXTSIZE];
char alias[ALIASIZE];
};
Here is a sample server(in C) send function:
send(iter->client.sockfd, (void *)se_packet, sizeof(s_packet), 0);
Here is a sample client recv function in C:
recv(m_sockfd, (void *)&se_packet, sizeof(s_packet),0);
printf("\x1b[3%dm <%s>: %s \x1b[0m\n", se_packet.text_color, se_packet.alias, se_packet.text);
I can read s_packet and separate in C, but How can I do it in java?
How can i separate like that in Java:
printf("\x1b[3%dm <%s>: %s \x1b[0m\n", se_packet.text_color, se_packet.alias, se_packet.text);
The definite answer is that it won't be so easy. The first thing you should understand is how tcp works. It's a stream oriented protocol and there's no such thing as a "message" in tcp. You just send and receive a stream of bytes.
In your snippet of code recv can finish after reading a part of message sent from the server. Instead you should keep a local buffer in java and drop all the data you've received so far. In a while loop you can detect if a message that is ready for processing was received. If your message is not very big (less than the MTU), then you may get lucky and always receive the whole 'message'. If you are not concerned with that then you may just use java.io.InputStream.read(byte[]) method.
The other thing to consider is how you interpret a message you received. Well you have no other choise but to process it as byte[] in Java. First you may want to read s_packet.text_color. It probably will be placed as first 4 bytes in a message. You can construct int from thoes bytes (see Convert 4 bytes to int for example). But this is not a good practice. This is because you send a binary data that is depends on how your s_packet is represented in memory. In real life you usually don't know what will be the size of int or char, it's platform dependent. Or sometimes the order of bytes inside int itself can differ. Instead you should declare your own serialization protocol and how your message is converted to binary data and vice versa.
Hope it helps.
Related
I want to pass different types of information from the client to the server via socket TCP (data transfer, prompt the server to call a function, ...) and they are on different threads, each receiving and transmitting a different type of information.
I'm passing data strings that have an integer added to the front to mark and use Switch-Case to classifying when received.
"1 This is a message" ---> Chat:"This is a message"
"2 asd" ---> function2("asd")
"3 Object1={{...}}" ---> Update object Object1
I think this way is not good. Which is the best way to do this?
so what you're looking for is Network Packets. Each packet has a header and a payload. You can think of each packet as containing an id to separate different packets from each other, as well as a length that determines the size of the incoming payload. Definitely checkout Netty, they do a lot of the work for you, including their amazing ByteBuf. Here is an example of how that might look.
byte[] payload = "Hello world!";
int length = payload.getBytes(Charsets.UTF_8);
Packet packet = new Packet(1, length, payload);
client.send(packet);
I have studies project. I my teacherd don't want to tell me how to solve problem with receive multiple files. I know I need to use function getInputStream() but I don't know how to split those files in this inputStream object. I need to split this inputStream beacuse I need to save each file in folder.
Thank you for your help and for explaining this problem to me.
The answer is that you probably need a transmission protocol like HTTP or FTP. But if you don't want something that high level, what you can do is tar and then gzip your files, which is what people did on unix back in the day. Tar is still basically a transmission protocol, but maybe not as heavyweight as HTTP or FTP
It sounds like your instructor wants you to create a protocol. The reason you will need a protocol is that if you send multiple files across the same socket you wont know when one file stops and another begins. To simplify the problem I will use a simple chat application as example, but the same will apply to files.
Lets say you have a chat app which has only 2 users (one server to client). Each user can send a message of any length. Lets say User1 wants to send User2 the following messages (each line is one message)
Hello User
How are you doing today?
If you send each of those raw messages across the socket you would likely get
Hello UserHow are you doing today?. Now how do you know where one message started and another stopped?
Simple solution is to send something before each message stating a length of characters in the upcoming message, so your message might be
11Hello User24How are you doing today?
So the end user knows that I read an int which tells me <length>, then read <length> characters to get a full message.
Now thats a pretty basic example and not super great. Lets look at a simple packet format I have seen used in a video game:
Field Name Field Type Notes
Length VarInt Length of packet data + length of the packet ID
Packet ID VarInt
Data Byte Array Depends on the connection state and packet ID, see the sections below
This is the basic format all information between the client and server uses. A length of data to be read, a packet type followed by its data for that packet type.
For your use case you likely need something similar, some sort of meta data about the bytes you are sending. EG: Length of file, file name.
I would start by looking at the DataInputStream class for easily reading primitive data types.
Basically I am doing some networking with a client and server sending "packets" back and forth to each other. I have it working with basic variable data such as ints or strings passing back and forth, however now I want to pass an object.
So I know I have to serialize the data of the object to pass it through the socket. That is working as well (as I can get the correct information if I serialize then de-serialize right away) but the problem comes in when my server receives a packet.
My server interprets packet data based on the first 2 characters of the packet. So 01foobar is a type of packet correlating to whatever "01" is assigned to and 02foobar is a different packet as well. So I don't know the best way to do this with an object attached. What is mean is this...
The way I have tried to do it right now is, serialize my object and get it's string. Then append on 03 to the front. So basically I have a string that looks like 03[B#3e9513b7 (or whatever) then do getBytes() on that string which gives me another byte[] (so I can send it through the socket). Then when the server receives that information, I can append the 03 off and I'm left with just [B#3e9513b7. The problem is, [B#3e9513b7 is now a string, and not a byte[] and in order to deserialize I need to send it the same byte[] as it gave me when it serialized that data. So that got me looking into a way to make [B#3e9513b7 BE the byte[] (aka, so when I do toString() on that new byte[] it returns [B#3e9513b7) but was having issues assigning it like that because it would give me a new byte[] for [B#3e9513b7 as a string. So obviously then, when I send it to be deserialized it has a byte[] that it doesn't know what to do with and throws an error.
So I have to imagine there's a better way to do this, and I'm just making things more complicated than they should be. Any recommendations? I can provide code snippets if needed.
Thanks guys!
Edit: I guess I should mention that I am using Java with using UDP sockets.
If you are looking for a reliable and efficient solution for client-server communication, I would suggest to look at Netty.
Regarding how to serialize/deserialize your objects, you have many choices as Java serialization, XML, JSON ...
You would have to pass your serialized objects in UDP datagrams. However, be aware that UDP datagram size is limited. If you're exchanging big objects, you may want to switch to TCP transport which is more reliable.
You may also want to look at SOAP/REST web services.
I'm trying to understand how platform independent socket communication works, because I would like to share socket data between a Java server and some native Unix and Windows clients. Sockets are platform independent by design, but the data representation is machine-related, hence it is advantageous if the TCP data abstracts the real data format, because a data format that is supported on one system doesn't have to be necessarily supported on another.
For example if I want to send an unsigned int value from a C++ client program to a Java server I must tell the server that this number should be interpreted as a negative integer. How does this kind of abstraction work? With my limited knowledge I would just send a number as text and then append some kind of unique character sequence that tells the receiver what kind of data he received, but I don't know if this is a viable approach.
To be a bit more concrete: I would like to send messages that contain the following content:
At the beginning of the message some kind of short signal or command
so that the receiver exactly knows what to do with the data that will follow.
Then some textual content of arbitrary length.
Followed by a number, which can be also text, but should be
interpreted separately.
At the end maybe a mark that tells the server that the message ends
here.
TCP processes the data in byte chunks. Does this mean when I write an UTF-8 encoded char in one byte that this char is interpreted in the same way on different machines if the client machines take Java's big endian byte order into account? Thanks for any input and help.
Sockets are independent but not the data transmitted in (Types length, byte order, String encoding, ...)
Look at Thrift, Protobuf or Avro if you want to send binary data with cross-languages and cross-platform functionnalities
I need to write an UDP server which will wait for packets from uncorrelated devices (max 10000 of them) sending small packets periodically; do some processing with the payload and write the results on SQL. Now I'm done with the SQL part through jdbc, but the payload bytes keep bugging me, how should I access them? Until now I've worked with the payload mapped to a string and then converting the string to hex (two hex chars representing one byte). I'm aware that there's a better way to do this but I don't know it...
Do you not just want to create a DatagramSocket and receive DatagramPackets on it?
You need to specify a maximum length of packet by virtue of the buffer you use to create it, but then you'll be able to find out how much data was actually sent in the packet using getLength().
See the Java Tutorial for more details and an example.