Stop and wait socket programming with UDP - java

Looking to make a Java stop-and-wait UDP server and client but I'm running into some problems starting off. I've made a simple UDP client and server without the stop-and-wait part, but I would now like to learn how to change it. How can I send ACKs and implement timeouts using java sockets ?
Could someone please post up some examples for me to use in my implementation ?

If you're implementing this in UDP, sending and receiving acknowledgements is up to you. This seems to be what you want for this stop and wait protocol. In terms of pseudocode, you would want something like:
int Send(msg)
{
char rcvBuf[];
sentBytes = sock.send(msg);
sock.rcv(rcvBuf);
return sentBytes;
}
int Recv(rcvBuf)
{
String ackMsg = "ACK";
length = sock.rcv(rcvBuf);
sock.send(ackMsg);
return length;
}
After every send, you wait for an acknowledgement message to come in, and every time you receive, you send an acknowledgement.

Related

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.

Listening to a multicast UDP address

I wrote an application in MATLAB to open a UDP socket and listen for incoming datagrams. Basically, something like this:
u = udp(rHost, rPort, 'LocalHost', lHost, 'LocalPort', lPort);
u.DatagramAvailableFcn = #(o,e) operateOnData(o,e);
fopen(u);
This works wonderfully when I'm listening to something in a unicast fashion. But I would now like to be able to listen to multicast traffic. Apparently, this isn't possible in MATLAB.
The workaround is, per above link,
As a workaround to connect to a UDP multicast, you can do the following:
Use a Java multicast socket to access it directly from MATLAB. For more information, see javadoc or tutorials for the "core java.net" classes from Sun, specifically "java.net.MulticastSocket". This could be found at:
http://java.sun.com/j2se/1.4.2/docs/api/java/net/MulticastSocket.html
I have no background in Java so this is a struggle for me. I've only been able to run the following to instantiate a MulticastSocket object:
>> ms = javaObject('java.net.MulticastSocket');
I looked around and found that I also need a java.net.Datagram object to actually contain the incoming stream.
How do I use the MulticastSocket and Datagram objects within the context of MATLAB? I'm trying to replicate the functionality of u.DatagramAvailableFcn, i.e., fire a callback to operate on the contents of the datagram once I receive one.
EDIT: Looks like this is how I want to go about this in terms of the Java, but now it's getting this back into MATLAB-land...
I successfully subscribed and received a packet from a multicast stream, by the following:
socket = java.net.MultiSocket(streamPort);
socket.joinGroup(java.net.InetAddress.getByName(streamIP));
socket.setReuseAddress(1);
packet = java.net.DatagramPacket(zeros(1, intmax('uint16'), 'int8'), intmax('uint16'));
socket.receive(packet);
socket.leaveGroup(InetAddress.getByName(streamIP));
socket.close;
msg = packet.getData;
msg = msg(1:packet.getLength);
This was essentially lifted from judp availble on the MathWorks File Exchange.
I am still looking for a way to get some equivalent of a DatagramReceivedFcn - right now it looks like the socket.receive call is blocking until it times out. I can use timer objects to fire the "callback" on a regular basis but that's of course not the same as having a DatagramReceivedFcn.

Basic principles of a UDP server with multiple clients

I'm implementing a FTP program using UDP in Java (TCP is not an option), but I'm having trouble grasping the basics of how it's supposed to work.
As I understand, it's connectionless, so I should just have one server thread running which processes every request by any client.
Where I'm getting confused is during the actual file transfer. If the server is in the middle of a loop sending datagrams containing bits of a requested file to the client, and is waiting for an ACK from the client, but instead of that receives a completely different request from a different client, how am I supposed to handle that?
I know I could jump out of the loop to handle it, but then if the initial expected packet finally arrives, how can I pick up where I left off?
A UDP server works similar to a TCP in many respects. The major difference is that you will not receive a acknowledgement that your packets were received. You still have to know which client you are sending to, so use the DatagramSocket class. This is the Oracle tutorial for UDP: http://docs.oracle.com/javase/tutorial/networking/datagrams/index.html. It has a pretty good example in it. The significant part is getting the address and port of the original client, and returning your packets to that client:
InetAddress address = packet.getAddress();
int port = packet.getPort();
new DatagramPacket(buf, buf.length, address, port);
You could start a new thread on the server side for sending the bits every time a client sends a request. The thread would save the return address and port of the client, and die when the file send was done.

Expanding my Java program to send a alert message to other computers

I've written a java intake program that send an PDF-formatted intake to a shared folder so that other people in the network can read it. However, there is not a way for the other people to know that an intake was sent unless someone tells them, so I want the program to send an alert message to the other computers telling them that an intake has been sent.
Now I've done some research into this and figured that TCP is the way to go since it's reliable. I also know that this is a one-to-many sending going on, so I assume that my Intake program will act as the server an the other computers will be the client, or should it be the other way around?
Now I assume that I have to create a client program that listens to the server and waits for it to send a message.
With that in mind, how do I:
Create a client program that listens for the message continuously until the program is closed. I assume that I'll be using "while (true)" and sleep. If so, how long do I put the program to sleep?
Make it as part of Windows service so that can load up when Windows start.
On the server end, how do I:
Send messages to more than one computer, since TCP is not capable of multicasting or broadcasting. I assume an array/vector will play a part here.
Oh, this is a one-way communication. The client doesn't have to respond back to the server.
First of all, UDP is quite reliable (in fact, as reliable as the IP protocol itself). TCP simply ensures that the data was received which involved quite a lot of magic in the back end. Unless you absolutely need to be sure that other machines got the message, you could do it with UDP. Mind that I'm not saying “Don't use TCP”, I just want to make it straight that you should take UDP into consideration as well.
Anyway, yes, you can create a simple listening program. Here is an example of a client in Java that reads messages from the server. It overrides the run method of a Thread class:
public void run() {
try {
String messageFromServer = reader.readLine();
while (messageFromServer != null) {
// Do things with messageFromServer here
// processor.processFromServer(messageFromServer);
messageFromServer = reader.readLine(); // Blocks the loop, waits for message
}
}
catch (IOException e) {
// Handle your exception
}
}
Amongst other things, my thread was set up as such:
public CommunicationThread(String hostname, int port, int timeout) throws IOException, SocketTimeoutException {
InetSocketAddress address = new InetSocketAddress(hostname, port);
socket = new Socket();
socket.connect(address, 2000); // 2000ms time out
// You can use the writer to write messages back out to the server
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
Now, regards to server-side you can do something as follows:
Write a program to allow clients to contact, given that they know your address.
Accept the connections, and store the sockets in a list.
When you need to send out a message, traverse the list and send the data to everyone on it.
You can start listening on your server with
this.socket = new ServerSocket(port);
You could (or even should(?)) make it threaded so that you can accept clients while serving others. You can accept new clients with:
socket.accept(); // Blocks, waiting for someone to connect, returns open socket
Feel free to pass that to a whole new class which can deal with BufferedWriter (and maybe even BufferedReader if you want to read from clients as well). That class is where you would implement things such as writeToClient(message)
Consider the situation where you have a ClientConnection class that has writeToClient(String s) method and (Server server, Socket socket) and initialized ArrayList conList.
Here is how you would follow:
In a separate thread in Server, accept connections with
ClientConnection con = new ClientConnection(this, socket.accept());
conList.add(con);
Then, when you want to write to clients:
for (ClientConnection c : conList) {
c.writeToClient("I'm sending you a message!");
}
I hope you get a vague idea of what you need to do. Read the Socket documentation, it's very useful. Also, as always with threaded applications, make sure you aren't doing things such as modifying a list while traversing it and avoid race conditions.
Good luck!

My ISP is forcing me to buffer tcp data before sending it

I have a Java TCP game server, I use java.net.ServerSocket and everything runs just fine, but recently my ISP did a some kind of an upgrade, where, if you send two packets very fast for the same TCP connexion, they close it by force.
This is why a lot of my players are disconnected randomly when there's a lot of traffic in game (when there is a lot of chance that the server will send 2 packets at same time for the same person)
Here is an example of what I mean:
If I do something like this, my ISP will close the connexion for no reason to both client and server side:
tcpOut.print("Hello.");
tcpOut.flush();
tcpOut.print("How are you?");
tcpOut.flush();
But it will work just fine if i do something like this:
tcpOut.print("Hello.");
tcpOut.flush();
Thread.sleep(200);
tcpOut.print("How are you?");
tcpOut.flush();
Or this:
tcpOut.print("Hello.");
tcpOut.print("How are you?");
tcpOut.flush();
This only started a couple of weeks ago when they (the ISP) did some changes to the service and the network. I noticed using Wireshark that you have to have at least ~150ms time between two packets for same TCP connexion or else it will close.
1)Do you guys know what is this called ? does is it even have a name ? Is it legal ?
Now I have to re-write my game server knowing that I use a method called: send(PrintWriter out, String packetData);
2)Is there any easy solution to ask java to buffer the data before it sends it to clients ? Or wait 150ms before each sending without having to rewrite the whole thing ? I did some googling but I can't find anything that deals with this problem. Any tips or information to help about this would be really appreciated, btw speed optimisation is very crucial. Thank you.
If your ISP imposes such quality of service policies and you have no way to negotiate them with it, I propose you enforce that rules on your side too with TCP/IP stack QoS configuration.
A flush marks your TCP packet as urgent (URG flag) so that it is sent whatever the buffer/TCP window state is. Now you have to tell your operating system or any network equipment on the line to either
ignore (or simply reset) the urgent flag when the previous packet has been sent in the last 150 ms and do some buffering if necessary
delay the delivery of consecutive urgent packets to honor the 150 ms constraint.
Probably an expensive software for Windows exists to do so. Personally, I think putting a Linux box as router between your Windows workstations and modem with the appropriate QoS settings in iptables and qdisc will do the trick.
You may create a Writer wrapper implementation to keep track of last flush call timestamp. A quick implementation is to add a wait call to honor the 150 ms delay between two consecutive flushes.
public class ControlledFlushWriter extends Writer {
private long enforcedDelay = 150;
private long lastFlush = 0;
private Writer delegated;
public ControlledFlushWriter(Writer writer, long flushDelay) {
this.delegated = writer:
this.enforcedDelay = flushDelay;
}
/* simple delegation for other abstract methods... */
public void flush() {
long now = System.currentTimeMillis();
if (now < lastFlush + enforcedDelay) {
try {
Thread.sleep(lastFlush + enforcedDelay - now);
} catch (InterruptedException e) {
// probably prefer to give up flushing
// instead of risking a connection reset !
return;
}
}
lastFlush = System.currentTimeMillis();
this.delegated.flush();
}
}
It now should be enough to wrap your existing PrintWriter with this ControlledFlushWriter to work-around your ISP QoS without re-writing all your application.
After all, it sounds reasonable to prevent a connection to flag any of its packet as urgent... In such a condition, it is difficult to implement a fair QoS link sharing.

Categories