Socket. Packets stay in queue when I need them - java

I have strange problem with receiving data from socket.
On client im using air socket. On server java netty.
Im writing to socket simple packets: int numPacket, int textLength, utf8String text. And read on client.
//server
buffer.writeInt( packetId );
ChannelBuffer ch = ChannelBuffers.copiedBuffer( text, CharsetUtil.UTF_8);
buffer.writeInt( text.length() );
buffer.writeBytes(ch);
//client
packetId = socket.readInt()
packetLen = socket.readInt()
text = socket.readUtfBytes(packetLen)
Sometimes one packets() doesnt receives by client, but server was send there, and tcpdump show that packet was send. If server send new packet, client read previous packet, and doesn't receivs new packet - and it's works like queue that im don't need.
p.s sorry for bad english -_-

Looks like client maybe waiting for some byte \n,\u etc to know the end of frame. I had similar problem with flash because the client was expecting a null byte at the end of the the transmission.
You could try to add the following sort of encoder as the last encoder in your pipeline and give it a try. The relevant code for handling nul byte is shown below.
ChannelBuffer nulBuffer = ChannelBuffers.wrappedBuffer(new byte[] { 0 });
ChannelBuffer buffer = ChannelBuffers.wrappedBuffer((ChannelBuffer)msg,nulBuffer);

Try using flush() on your buffer after each or all three

Related

UDP response packet contents getting cut short

I'm trying to create a simple Java UDP Client-Server program. The server/host waits for an appropriate request from the client before doing something. Everything seems to be working fine but the reply from the host to the client is always truncated for some reason.
I assume it has something to do with the the length of "Bob" as all responses from the host is shortened to 3. I tried messing around with setLength() and the buffer size but can't seem to figure it out...
Client.java:
public class Client {
public static void main(String[] args) throws Exception {
//Use Java's built-in DatagramSocket and DatagramPacket to implement UDP
DatagramSocket socket = new DatagramSocket(); //Create socket object to send data
socket.setSoTimeout(5000); //Throw an exception if no data received within 5000ms
//Create scanner to grab user input
Scanner input = new Scanner(System.in);
System.out.print("Please enter a message to send to Alice: ");
String bobInput = input.nextLine(); //Storing user input
input.close(); //Close scanner to prevent memory leaks
byte[] buffer = new byte[65535];
//Create packet containing message
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 1500);
packet.setData(bobInput.getBytes());
socket.send(packet); //Send message to host
socket.receive(packet);
System.out.println("Received from Alice: " + new String(packet.getData(),0,packet.getLength()));
socket.close();
}
}
Host.java
public class Host {
public static void main(String[] args) throws Exception {
//Use Java's built-in DatagramSocket and DatagramPacket to implement UDP
DatagramSocket socket = new DatagramSocket(1500); //Create a socket to listen at port 1500
byte[] buf = new byte[65535]; //Byte array to wrap
System.out.println("Parameters successfully read. Listening on port 1500...");
//While-loop to keep host running until terminated
while (true) {
DatagramPacket packet = new DatagramPacket(buf, buf.length); //Create a packet to receive message
socket.receive(packet); //Receive the packet
//If Alice receives a packet with the message "Bob"
if(new String(packet.getData(),0,packet.getLength()).equals("Bob")) {
System.out.println("Bob has sent a connection request.");
String test = "Hello Bob!";
packet.setData(test.getBytes());
System.out.println("Text sent: " + new String(packet.getData(),0,packet.getLength()));
}
}
}
}
Console output for client:
Please enter a message to send to Alice: Bob
Received from Alice: Hel
Console output for host:
Parameters successfully read. Listening on port 1500...
Bob has sent a connection request.
Text sent: Hello Bob!
It's my first time working with UDP so I apologize if its some basic mistake that I made.
In the client, you create a packet of length 3 (because the content is 'Bob'). You use the same packet for a receive, which per the doc will then truncate the received data to the packet length.
The DatagramPacket class does not appear to distinguish 'length of underlying buffer' from 'length of data in buffer'.
Best to use separate packet structures; the send packet just needs to contain 'Bob'; the receive packet needs to be large enough for the maximum expected response.
(Debugging hint: figuring this out starts with noticing that it's unlikely to be mere coincidence that the lengths of the transmitted message and of the truncated received message are identical).
Typically, in cases like this, you should create a custom protocol, either textual or binary, in which you specifies the length of the message to be read; it is not a TCP, so you can only wait until the entire datagram has been sent or received and after that parse the contents and extract the message.
This requires defining your own protocol to be used on top of UDP; there are two macro types of protocols: text-type and binary-type.
In text-type protocols you often make use of integers to put as prefixes that indicate the actual length of the message to be read. In fact if you know that the length of your messages, for example, stands at 32bit you can read the first four bytes of the datagram and know how many more you will have to read to get your string. The more complex text protocols make use of delimiting characters to specify a format that defines options and data; of this family you will certainly be familiar with HTTP.
In binary-type protocols it is a little more complex, you can have flags, various lengths referring to different fields that may or may not be optional.
In short in this case you have to define for yourself a frame type to use and interpret. If you have to deal with fragmentation, options and variable lengths, I would recommend that you take a look at this type of format.
Keep also in mind that with UDP you should in real projects also handle the retransmission of lost packets.
Anyway, it's probably a typo, but your code is definitely missing a send() that actually sends the response data.
So from your code we can't see what you actually send.
In conclusion, to answer you, from what can be inferred from the part of the code given and the output provided, you make use of setData() to send "Bob." The documentation for that method is as follows:
Set the data buffer for this packet. With the offset of this
DatagramPacket set to 0, and the length set to the length of buf.
So, no matter what buffer you initialized the datagram with it will now be reduced to a maximum length of three. In fact, when you receive the response you read the message with getLength() which will always return three.

Java tcp socket does not receive properly

Hi let me get straight to the problem. I have a big JSON packet that the server sends to this client once the client is authenticated
But the packet comes back in a weird way like it's split or something example:
The JSON should be:
Received: {"UserID":1,"PlayerID":2,"EXP":0,"Lvl":1,"Coins":0,"ItemSlots":30}
When it comes through:
Received: {"UserID":1,"PlayerID":2,"EXP":0,"Lvl":1,"Coins":0,
Received: "ItemSlots":30}
Why does it split the packet or something when it comes to the client and how can I fix this anyway?
Java Receive Code:
private class ClientThread extends Thread {
public void run() {
try {
while (selector.select() > 0) {
for (SelectionKey sk : selector.selectedKeys()) {
selector.selectedKeys().remove(sk);
if (sk.isReadable()) {
SocketChannel sc = (SocketChannel)sk.channel();
ByteBuffer buff = ByteBuffer.allocate(1024);
String content = "";
while (sc.read(buff) > 0) {
sc.read(buff);
buff.flip();
content += charset.decode(buff);
buff.clear();
}
System.out.println("Recieved: " + content);
sk.interestOps(SelectionKey.OP_READ);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Thanks have a wonderful day.
Hi lemme get straight to the problem so i got a big JSON packet that the server sends to this client once the client is authenticated
You mean you have a big JSON message. Packets are things that network protocols used to exchange information.
But the packet comes back in a weird way like its split or something example:
Unless you're looking at the wire, you aren't looking at packets. You're looking at the bytes you got from your end of the TCP connection.
The JSON should be:
Recieved: {"UserID":1,"PlayerID":2,"EXP":0,"Lvl":1,"Coins":0,"ItemSlots":30}
When it comes through:
Recieved: {"UserID":1,"PlayerID":2,"EXP":0,"Lvl":1,"Coins":0,
Recieved: "ItemSlots":30}
Excellent. You got the same bytes. Now make a JSON parser that figures out where the message ends and parses it.
Why does it split the packet or something when it comes to the client
It splits the message into packets because that's how TCP gets the message to the other side. TCP is not a message protocol and it doesn't know or care what the application considers to be a message -- that's the application's job.
and how i can i fix this anyway?
Write a JSON parser to figure out where the messages end. You haven't implemented any code to receive JSON over TCP yet, so that won't work until you do.
TL;DR: If you want an application-level message protocol, you need to implement one. TCP is not one.
TCP protocol does not maintain message boundaries. It is not guaranteed that what the server sends is received as-is by the client and vice-versa.
If the server sends 1000 bytes data, the client application can receive the same across multiple recv or single recv. TCP does not guarantee any behaviour. "Split" can happen, it is upto the application to handle the data coming in multiple chunks, coalesce it to one unit of application data for further processing. One can see this particularly with large data sizes.
It looks like you've got a non-blocking socket channel, meaning that the while (sc.read(buff) > 0) { loop is terminating due to sc.read(buff) returning 0 since only a portion of the data sent has, at this point, been received.
Why does it split the packet or something when it comes to the client
Most likely the data is being split into two or more packets.
and how i can i fix this anyway?
Keep filling your buffer until the socket is closed by the server (read should return -1 rather than 0 in that case). You need to maintain a separate buffer per channel. If the server doesn't close its end after sending the data, you'll need to delineate in some other way; you could prefix the JSON blob with a size header, for instance.

Do UDP packets arrive in entirety?

I know that TCP simulates a stream, so typically reads will start as soon as any data is received. Thats why I use this snippet to make sure it waits for the entire packet before acting on it
int packetSize = inputStream.readShort() ;
byte packetBuffer[] = new byte[packetSize];
int byteTrans = 0;
while ( byteTrans < packetSize )
{
inputStream.read( packetBuffer , byteTrans , 1 );
byteTrans++;
}//
For UDP however, will I still have to work around the same problem? I don't think so because TCP basically simulates a stream by breaking up your data into smaller packets and sending it, while in UDP you have more control over the whole process.
For reading UDP I use
byte[] packetByte = new byte[packetSize];
DatagramPacket packet = new DatagramPacket(packetByte, packetByte.length);
socket.receive(packet);
Do I have to implement a similar system for UDP?
When you send a datagram packet, it will be received in its entirety, yes (when it is actually received - continue reading the answer).
The behavior of UDP and TCP varies in much more than just that. UDP does not guarantee packets will be received in the same order they are sent (or even received at all) or that they are recevied exactly once. UDP is more of a "fire and forget", whereas TCP maintains a connection state.
In short, if the packet is received, you will get the whole packet. But it may not be received at all.

Socket C client and Java server can send only one String

My Java server sends an Integer and a String (to a C client):
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeInt(ClientNumber); //send the Integer
String randomString= getRandomValue(10,20);
dos.writeUTF(randomString); //send the String
String clientString=din.readLine();
The C code for the client that's reading them is:
if( recv( to_server_socket, &reply, sizeof( reply ), MSG_WAITALL ) != sizeof( reply ) )
{
printf( "socket read failed");
exit( -1 );
}
char buf[50];
int byte_count;
byte_count = recv(to_server_socket, buf, sizeof buf, 0);
printf("recv()'d %d bytes of data in buf\n", byte_count)
Until here, it works fine.
Now, I want to send another String to the Client. So, I tried just adding the line:
dos.writeUTF("blabla");
It's still working and when I tried to get the client to read it, I added:
byte_count2 = recv(to_server_socket, buf2, sizeof buf2, 0);
printf("recv()'d %d bytes of data in buf\n", byte_count2);
And it doesn't work. The client receives the number and the first String but it doesn't send anything and doesn't receive the "blabla" string. I'm not sure if the problem is in the client or the server.
Can anyone explain to me what I'm doing wrong?
Try closing your dos(DataOutpuStream) after every write. You may try to check first if flush helps.
You are mixing your protocols. I suggest you use either binary or text wire format. It's not clear which one you are trying to use.
I suggest text wire format as it is easier to work with in this case. i.e. don't DataInputStream or DataOutputStream as these are for binary formats.
Instead you can use BufferedReader for reading lines of text and PrintWriter for writing lines of text. You can test your server works by connecting to it with telnet i.e. if it doesn't work with telnet, it won't work with C.
Once this is working, get your C client to work as well. BTW You shouldn't assume that one write translates to one read. You are writing a Stream of data, not messages.

UDP packet separation

I'm creating an UDP service on andorid.
For clarity part of the code copied here:
byte[] message = new byte[1500];
DatagramPacket packet = new DatagramPacket(message, message.length);
socket = new DatagramSocket(Constants.LISTENING_PORT_NUMBER);
socket.receive(packet);
Problem is that I'm receiving UDP packets continuously.
For example packet #1 (250 byte long), packet #2 (182 byte long), packet #3 (403 byte long) etc...
I need to get and process the separate UDP packets which has variable length.
According to UDP protocol specification UDP packets has message boundaries defined.
However I found no solution in Java which can separate UDP packets.
In my current solution I have to define the packet length which I must read, but I don't know the packet length before I receive it.
Am I missing a point?
EDIT:
Thanks for both Tobias and shazin both are correct answers. Sad I cant's mark two answer as correct.
The socket.receive(packet); will receive until the UDP packet boundary, subsequent packages can be read with another socket.receive(packet);.
My problem should be that during the process of the first message the arrived further messages are not processed because of synchronous processing, now I'll pass the message processing to an async task and hopefully will be able to catch all arrived packets in time.
You cannot know the packet length before hand. You can define a maximum boundary bytes array based on the data you may be receiving. 2048 byte array is recommended.
byte[] message = new byte[2048];
Even if you have variable length in incoming message packets, you can use the following code to receive
byte[] message = new byte[2048];
DatagramPacket packet = new DatagramPacket(message, message.length);
socket = new DatagramSocket(Constants.LISTENING_PORT_NUMBER);
socket.receive(packet);
String data = new String(packet.getData(), 0, packet.getLength());
getData and getLength methods can be used to determine the size of the received packet.
Maybe I'm missing something here, but a DatagramPacket is one packet that is sent. It has the getLength() and getOffset() methods require to get to the data. I believe that there is also a getData() that returns the data sent.
Here you have a link That can help you further.

Categories