Java high speed udp traffic packet receiving for bandwidth testing - java

I am trying to build a bandwidth testing tool, kind of like IPerf but in java, I seem to be getting more packet loss than expected however at slightly higher bandwidths (starts at about 30-40Mb/s) and I was hoping someone could possibly point out some optimization or something that I am doing wrong that would cause me to be missing packets.
this is the receiving code, which hands off queues of size 2000 to another class which gathers metrics, it only passes relevant information from the packet. using NIO
while (data.isRunning())
{
if(channel.receive(buf) != null)
{
int j = buf.array().length;
//add the packets important information to the queue
packet_info.add(new PacketInfoContainer(buf.getLong(j-12), System.nanoTime(), buf.getInt(j-4)));
// if we have 2000 packets worth of information, time to handle it!
if((packet_info.size() == 2000))
{
Runnable r1;
//if this is running on the client side, do it this way so that we can calculate progress
if(client_side)
{
if(data_con.isUserRequestStop())
{
System.out.println("suposed to quit");
data.stopTest();
break;
}
if(packets_expected > 0)
{
total_packets_received+=1000;
setChanged();
notifyObservers("update_progress" + Integer.toString( (int) (((double)total_packets_received/(double)packets_expected) * 1000) ) );
}
r1 = new PacketHandler(packet_info, results, buffer_size, client);
}
//server side, no nonsense
else
{
r1 = new PacketHandler(packet_info, results, buffer_size);
}
pool.submit(r1);
packet_info = new LinkedList<PacketInfoContainer>();
}
}
buf.clear();
}

UDP is not very well... may be you can use TCP & check tcp stats of S.O. to see retransmissions...
netstat -s
you can use CharacterGenerator, change BufferedOutputStream to 64KB and removing os.flush(); to speedup and test...

It won't allow me to comment yet, here I go.
You shouldn't be seeing dropped packets until the wire limit is hit. I suggest isolating the problem of dropped packets and using tools to figure out if you have a hardware / environment problem before spending lots of time looking at your code.
https://serverfault.com/questions/561107/how-to-find-out-the-reasons-why-the-network-interface-is-dropping-packets
Have you tried to run iperf in UDP mode? then check the dropped packet statistics? https://iperf.fr/iperf-doc.php
bmon is a neat tool that will show you the carrier error, dropped, fifo error stats.

Related

How can I keep TCP packets from being dropped?

I'm creating a program on my Android phone to send the output of the camera to a server on the same network. Here is my Java code:
camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera cam) {
try {
socket = new Socket("XXX.XXX.XXX.XXX", 3000);
out = socket.getOutputStream();
out.write(data);
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
camera.addCallbackBuffer(data);
}
The server is a NodeJS server:
time = 0
video_server.on 'connection', (socket) ->
buffer = []
socket.on 'data', (data) ->
buffer.push data
socket.on 'end', ->
new_time = (new Date()).getTime()
fps = Math.round(1000/(new_time - time)*100)/100
console.log fps
time = new_time
stream = fs.createWriteStream 'image.jpg'
stream.on 'close', ->
console.log 'Image saved.', fps
stream.write data for data in buffer
stream.end()
My terminal is showing about 1.5 fps (5 Mbps). I know very little about network programming, but I do know there should definitely be enough bandwidth. Each image is 640x480x1.5 at 18 fps, which is about 63 Mbps. The local network should easily be able to handle this, but my debugger in Android is giving me a lot of "Connection refused" messages.
Any help on fixing my bad network practices would be great. (I'll get to image compression in a little bit -- but right now I need to optimize this step).
You've designed the system so that it has to do many times more work than it should have to do. You're requiring a connection to be built up and torn down for each frame transferred. That is not only killing your throughput, but it can also run you out of resources.
With a sane design, all that would be required to transfer a frame is to send and receive the frame data. With your design, for each frame, a TCP connection has to be built up (3 steps), the frame data has to be sent and received, and the TCP connection has to be torn down. Worse, the receiver cannot know it has received all of the frame data until the connection shutdown occurs. So this cannot be hidden in the background.
Design a sane protocol and the problems will go away.
Is this working at all? I do not see where you are binding to port 3000 on the server.
In any case, if this is a video stream, you should probably be using UDP instead of TCP. In UDP, packets may be dropped, but for a video stream this will probably not be noticeable. UDP communication requires much less overhead than TCP due to the number of messages exchanged. TCP contains a lot of "acking" to make sure each piece of data reaches its destination; UDP doesn't care, and thus sends less packets. In my experience, UDP based code is generally less complex than TCP based code.
_ryan

Java Socket Connection is flooding network OR resulting in high ping

i have a little problem with my java socket code.
I'm writing an android client application which is sending data to a java multithreaded socket server on my pc through direct(!) wireless connection. It works fine but i want to improve it for mobile applications as it is very power consuming by now. When i remove two special lines in my code, the cpu usage of my mobile device (htc one x) is totally okay but then my connection seems to have high ping rates or something like that...
Here is a server code snippet where i receive the clients data:
while(true)
{
try {
....
Object obj = in.readObject();
if(obj != null) {
Class clazz = obj.getClass();
String className = clazz.getName();
if(className.equals("java.lang.String")) {
String cmd = (String)obj;
if(cmd.equals("dc")) {
System.out.println("Client "+id+" disconnected!");
Server.connectedClients[id-1] = false;
break;
}
if(cmd.substring(0,1).equals("!")) {
robot.keyRelease(PlayerEnum.getKey(cmd,id));
}
else {
robot.keyPress(PlayerEnum.getKey(cmd,id));
}
}
}
} catch ....
Heres the client part, where i send my data in a while loop:
private void networking() {
try {
if(client != null) {
....
out.writeObject(sendQueue.poll());
....
}
} catch ....
when i write it this why, i send data everytime the while loop gets executed.. when sendQueue is empty, a null "Object" will be send. this results in "high" network traffic and in "high" cpu usage. BUT: all send comments are received nearly immediately.
when i change the code to following:
while(true)
...
if(sendQueue.peek() != null) {
out.writeObject(sendQueue.poll());
}
...
the cpu usage is totally okay but i'm getting some laggs.. the commands do not arrive fast enough.. as i said, it works fine (besides cpu usage) if i'm sending data(with that null objects) every while execution. but i'm sure that this is very rough coding style because i'm kind of flooding the network. any hints?
what am i doing wrong??
Thanks for your Help!
Sincerly yours,
maaft
The CPU-intensive version of your code is flooding the output stream with null values. They count as data to be transmitted. Although your server explicitly ignores them, they are helping to to eventually force any useful data through as well.
Your modified code with the peek is more reasonable. It is good form to call flush after writeObject. The written object could otherwise be stuck in output buffers and waiting for more items to come. Buffering is a performance optimization for cases where many objects are sent together. Flushing is not needed with stream classes that do not do buffering.
Even better:
Object item = sendQueue.poll();
if (item != null) {
out.writeObject(item);
out.flush(); // maybe not needed, depending on the class of your stream
}
This is slightly faster; there is no point in evaluating peek if you intend to poll immediately anyway.
Furthermore, call socket.setTcpNoDelay(true) on the socket before you pass it to the SocketOutputStream (assuming that is how you create the output streams). That disables the Nagle algorithm which may not necessarily be the best decision for conservation of network bandwidth, but it is a quick way to check that apart from tuning TCP send/receive buffers your client and server work correctly. If you have a direct connection to your server I would not worry about disabling Nagle algorithm at all.
You should use a blocking queue so that poll() blocks, rather than returning null. There is no point in sending the nulls at all, it's just a waste of everybody's time, bandwidth, and money.
Just as a further note, you might want to take a look at the ARO tool for Android that helps you to do optimization of your app including network usage. http://developer.att.com/developer/legalAgreementPage.jsp?passedItemId=9700312

Java -> C++ TCP Socket does not send until close

I am facing another TCP Socket issue.
I've read through a huge bunch of questions an answers to similar issues, but my problem is somehow different.
I have a Java Client and C++ Server. Everything goes as expected until I'm using different machines (equal to other issues so far)
The messages from the client seem to getting stuck in den TCP Buffer. When I finally close the socket, everything is sent to the server. But these single messages are controlmessages so I need them to be send immediatly. As far as I read this is expected behavior, but how do I send reliable control messages.
Is there a way to force the messages to be sent. (I can leave the socket open for a couple of minutes with nothing is sent.)
Is there something wrong? (see the following code)
Do I have to close the socket each time to perform a REAL flush?
Should I use UDP instead, with an additional amount of protocol work?
Javacode:
mSocketSend = new Socket();
mSocketSend.connect(new InetSocketAddress(mServerIp, mSocketPortSend), mTimeOut);
PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);
C++ Code:
opening socket...(i leave that)
char* buffer = new char[1024];
int rc = recv(mConnectedSocket, buf, 1024, 0);
If you want more of it. Write it. I left almost everything out. ^^ I dont think its relevant. The Communication wents great usually.. No errors at all. So its just this TCPBuffer thingi.
I know there should be some delimiter or message length stuff. But in fact: A message length, which is not sent, does not help. ^^
Thanks for your help.
EDIT #01 The whole bunch of code:
mSocket->createSocketServer(22);
char* buffer = new char[1024];
while(true){
int numberBytes = mSocket->receiveChars(buffer, 1024);
if (numberBytes > 0){
uninterestingHandlingFunction(buffer);
}else{
mSocket->createSocketServer(22);
}
}
bool Socket::createSocketServer(u_short port)
{
if (mConnectedSocket != INVALID_SOCKET)
{
closesocket(mConnectedSocket);
}
if (s == INVALID_SOCKET)
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2,0), &wsa) != 0)
return 0;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
return 0;
SOCKADDR_IN addr;
memset(&addr, 0, sizeof(SOCKADDR_IN));
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=ADDR_ANY;
if (bind(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
s = INVALID_SOCKET;
} else if (listen(s, 10) == SOCKET_ERROR)
{
s = INVALID_SOCKET;
}
if (s == INVALID_SOCKET)
{
closesocket(s);
return 0;
}
}
mConnectedSocket = accept(s, NULL, NULL);
if (mConnectedSocket == INVALID_SOCKET)
{
closesocket(s);
return 0;
}
return 1;
}
int Socket::receiveChars(char* buf, unsigned maxSize)
{
if (mConnectedSocket == INVALID_SOCKET)
return -1;
int rc = recv(mConnectedSocket, buf, maxSize, 0);
if (rc == SOCKET_ERROR)
{
std::cout << "Socket: error " << WSAGetLastError() << std::endl;
}
return rc;
}
You wanted it....
EDIT #2 Give it one more try
There are few more things I tried out.
At first: This problem does not occure on a device connected over real network everytime. -> Full Reboot Client&Server -> Problem does not occure -> Full Reboot Client&Server -> Problem occures
Sadly, I don't know what to take from this habit.
Another thing I stumbled over is the bind and listen socket (in Code SOCKET s). This socket listens for connections and if the working thread needs a new connection (on startup or if the previous closes) the socket s gives the next queued connection to mConnectedSocket for recv, other connections are backlogged while one is processed.
From the Java view: a Socket is connected (Device A). next socket (Device B) tries to connect. -> Connection success (its properly controlled in code if this is happens indeed) -> followed by sending data in natural matter. (The socket is still in the backlog on c++ side)
Well, this is hard to transform to the habit I experienced. I'll try to express my thoughts.
Javaside: PrintWriter is created. Feeded with data and is flushed. Because the connection is not fully established (No additional connectedSocket on C++ side). The flush doesn't work. And onClose the socket finally flushes its content.
Please tell me to shut up, if you think so. I dont really know what the "Connection is backlogged" ACTUALLY mean in implementation" ^^
I know, I should open a new thread for each connection, but I can't at the moment. So stick with this server code.
You need to do a flush(), that pushes the data out.
PrintWriter.flush();
Or use a writer with automatic flushing.
You should also make sure that the server reads a line (until \n) and not the full 1024 chars, but I don't know what recv() does so I don't know about that.
Fixed it. Kind of embarassing...
The backlog, i noticed in my edit was indeed the problem.
If two at clients at a time connect to the server, the second is backlogged and his messages would be processed, when the first disconnects.
Additionally (here comes the clue)
As mentioned before its an android java client. There is another thread on java side to receive data from the C++ server. This socket connects on another port.
BUT i set the ports and ip addresses to connect to in a settings activity and there was a bad port for the other socket as default value (same as for the issuesocket, wrong variable taken)
So this socket connects first and the issuesocket connects into the backlog.
This default value is only taken if I enter the settings to set another IPAddress (For example, when I connect to a remote host instead of localhost)
Incredible circumstances... i didnt even wrote the settings...
WIRESHARK would have fixed this.
PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);
pw.flush();
Actually your problem could be on the receiving end, your recv needs to be in a loop (you can google for examples of this). There is no guarantee not much each call to recv will get. If you know you are flushing the data on the Java site, that's probably your problem.
As you are using auto flush and even tried using an explicit flush():
Could be because you don't open the inputStream. Try and do a getInputStream() as well.
Otherwise, Have you tried:
any diff you don't use connect but just give the parameters directly in the Socket constructor?
setTcpNoDelayon the socket (shouldn't cause minutes of delay though!!)?
Your loop is incorrectly coded. Every new recv() will overwrite the previous one. You should advance the offset parameter.

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.

Read netflow/rflow (dd-wrt) packet content

I'm currently developing an IDS/IPS that uses NetFlow data to draw assumptions whether there is an ongoing attack. I didn't afford an expensive CISCO router so I bought a LINKSYS router on which I installed DD-WRT. DD-WRT sends netflow v5 packets to your preferred machine so it's like having a CISCO router but older. Basically you get a $200-$500 router for $80 and a little tweaking.
I've set up the router, I'm getting the packets, I even used the DD-WRT provided tool for capturing rFlow (they named it like that but it's netflow v5) and everything works.
My application will have to do everything internally so that means i need to capture rflow packets, read them and draw the assumptions based on my readings.
I started developing in JAVA and set up a UDP daemon to listen on 2055 (port for receiving rflow packets). All good, i'm getting the packets but when i try to view the content i get some weird characters, like I'm dumping stuff from memory.
Here's my code for setting up the deamon and reading data.
try {
serverSocket = new DatagramSocket(2055);
while (true) {
DatagramPacket receivedPacket = new DatagramPacket(received, received.length);
serverSocket.receive(receivedPacket);
ByteArrayInputStream byteIn = new ByteArrayInputStream(receivedPacket.getData(),0,receivedPacket.getLength());
DataInputStream in = new DataInputStream(byteIn);
String input = "";
while( (input = in.readLine()) != null) {
System.out.println(input + "\n");
}
Inet4Address from = (Inet4Address) receivedPacket.getAddress();
System.out.println("FROM: " + from + "\nDATA: " + data[4]);
}
} catch (SocketException ex) {
System.out.println(ex.getMessage());
}
I have found a library called jflow..but there is no source code so i'm pretty skeptical on using it. I was wondering if somebody can tell me how can i actually read the content of the packets being sent to me. Since i'm at an early stage of development I am not bound to use JAVA, i could go for C++. My biggest problem, no matter the programming language is how to read the content of those packets so that I can draw the correct conclusions that i need for my other modules.
The rFlow / NetFlow v5 packets are a binary packet layout, so viewed as text they will appear, well, unreadable.
The packet format for the v5 packets is known, and can be found with a google search. This seems a good reference.
Note that the rFlow daemon on the dd-wrt has a long standing bug where it does not fill in the input or output interface fields correctly.

Categories