reading data from socket - no performance - java

I am creating an android service which is always running and listening messages from socket. But it doesn't work with good performance and i am looking for some nio alternative or tutorial.
What is the best way for listening a socket for all time ?
Does AndroidAsync support standart sockets ? https://github.com/koush/AndroidAsync
Is there anyone used Apache Mina ? I am having character problem with Mina. http://mina.apache.org/
Or how can i do this job with good performance using standart sockets
Waiting for your experiences.
Thanks

The normal way to get decent performance from a socket (for int read() and write(int)) is to use a buffered stream / reader / writer. That reduces the number of system calls and makes byte or character at a time I/O much faster.
I don't expect that using NIO will make a significant difference. If the problem is not buffering, then (IMO) it is probably a network bandwidth and/or latency issue. If that is the case, there is little that you can do in Java that would make much difference.

I have some convenience methods for writing strings with java.nio:
private static Charset charset;
static
{
charset = Charset.forName("UTF-8");
}
public static void writeString(SocketChannel sc, String string) throws IOException {
CharBuffer c = CharBuffer.wrap(string);
ByteBuffer b = charset.encode(c);
b.compact();
b.flip();
sc.write(b);
}
public static String readString(SocketChannel sc) throws IOException {
ByteBuffer bbuf = ByteBuffer.allocate(8096);
sc.read(bbuf);
bbuf.flip();
CharBuffer cbuf = charset.decode(bbuf);
return cbuf.toString();
}
All you need to do is establish your SocketChannel connections and you can use these all you want. java.nio is really not that difficult once you get used to it :)

Related

UDP library for Java that works garbage free

I'm looking for a UDP library for Java that works garbage free.
The reason is that i'm developing a daemon application for a real-time system.
My requirement is latency of 5 micro-sec per request (from arrival to my socket until the response gets to destination).
There are a couple of messaging services who support UDP and produce no garbage (Tibco FTL & Aeron), but both require that all communicating components will use the flatform.
My situation is that I have no control over the other components, all I know is that i'm going to get UDP messages to my socket and I need to handle them without producing any garbage.
Will appreciate any ideas :)
What do you mean by no garbage ? In UDP you may lose messages, this is inherent to this protocol. If you want to have some reliability on top of UDP you need to have an additional layer to manage acks, retransmissions and etc.. This means that your producer and consumer applications have to use this layer API to send / receive messages.
A very short example of this is just:
import java.lang.System;
public class UdpNoGc {
public static void main(String[] args) throws Exception {
var buf = new byte[1024];
var pkt = new java.net.DatagramPacket(buf, buf.length);
try (var sock = new java.net.DatagramSocket(4321)) {
for (;;) {
sock.receive(pkt);
System.out.write(buf, 0, pkt.getLength());
System.gc();
}
}
}
}
the explicit System.gc() call is just there so you can run with:
java "-Xlog:gc,heap*" UdpNoGc
and see that it doesn't allocate anything after startup. Note that writing code that doesn't allocate is somewhat difficult in Java, it might be easier using another language that provides more support for this.

Java NIO FileChannel - Empty reads from Android TUN network interface

Context: I've recently started using java.nio for my project which leverages Android's VpnService. In my implementation, I've wrapped the FileDescriptor that is returned by the establish() method of the VpnService into a java.nio.FileChannel as shown below.
private val outboundNetworkChannel = FileInputStream(fd).channel
After that, I've a kotlin coroutine which reads from the FileChannel indefinitely and processes the outbound IPv4 / IPv6 packets.
Issue: The below mentioned snippet works, but I see a lot of empty reads happening from the FileChannel which in turn spins the while loop unnecessarily.
fun reader() = scope.launch(handler) {
while (isActive) {
val pkt = read()
if(pkt !== DUMMY){
// Send the read IPv4/IPv6 packet for processing
}
}
}
private suspend fun read(): IPDatagram =
withContext(Dispatchers.IO) {
val bytes = ByteBufferPool.acquire()
outboundChannel.read(bytes) // Returns a lot of empty reads with return value as 0
return#withContext marshal(bytes) // Read IPv4/IPv6 headers and wrap the packet
}
What I'm looking for: For a fact, I know that FileChannel is a blocking channel and in this case since the channel is backed by a network interface, it might not have packets ready to be read. Is there a better approach with / without FileChannel which would lead to a more efficient implementation without wasting precious CPU cycles? I'm open to new ideas as well :)
I managed to figure this out after digging through the Android Docs for VpnService. By default, when a VPN connection is established using VpnService.Builder the fd is in non-blocking mode. Starting API level 21, one can setBlocking(true).
As stated in the docs for public VpnService.Builder setBlocking (boolean blocking)
Sets the VPN interface's file descriptor to be in
blocking/non-blocking mode. By default, the file descriptor returned
by establish() is non-blocking.

How do I use Google protobuf to communicate over a serial port?

I'm working on a project that uses RXTX and protobuf to communicate with an application on a development board and I've been running into issues which implies that I'm likely doing things the wrong way. Here's what I currently have for writing the request to the board (the read code is similar):
public void write(CableCommandRequest request, OutputStream out) {
CodedOutputStream outStream = CodedOutputStream.newInstance(out);
request.writeTo(outStreatm);
outStream.flush();
}
The following is the setting that are used to prepare the RXTX serial connection which in turn suplies the OutputStream used by the write command:
// The baud rate to use when connecting to the development board
private final static int BAUD_RATE = 115200;
// The timeout to use for the serial port
private final static int CONNECTION_TIMEOUT = 50;
// The serial break for the development board, 100
private final static int SERIAL_BREAK = 100;
// <SNIP> ...
SerialPort serialPort = (SerialPort)port.open(appName, CONNECTION_TIMEOUT);
serialPort.setSerialPortParams(BAUD_RATE,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
serialPort.sendBreak(SERIAL_BREAK);
The OutputStream that is used is prepared by RXTX and the development board seems to indicate that data is being received, but it is getting garbled or is otherwise not being understood.
So far all of the usual suspects (e.g. serial connection not being established, communication issues, etc.) have been eliminated so it appears that the problem is in how the call to writeTo is made since communications over the serial connection are successful.
There seems to be little documentation on using protobuf over a serial connection so I'm assuming that passing the OutputStream should be sufficient. Is this in fact correct, or is this the wrong way of sending the response over the serial connection?
Protocol Buffer values are encoded using little-endian byte order on the wire. This is ordinarily irrelevant when Protocol Buffers are use on both ends, but it may pose a problem in this context. If so, you may be able to use java.nio.ByteBuffer to effect the conversion, as suggested here.

Simulate back pressure in TCP send

I am writing some java TCP/IP networking code ( client - server ) in which I have to deal with scenarios where the sends are much faster than the receives , thus blocking the send operations at one end. ( because the send and recv buffers fill up ). In order to design my code , I wanted to first play around these kind of situations first and see how the client and servers behave under varying load. But I am not able to set the parameters appropriately for acheiving this back pressure. I tried setting Socket.setSendBufferSize(int size) and Socket.setReceiveBufferSize(int size) to small values - hoping that would fill up soon, but I can see that send operation completes without waiting for the client to consume enough data already written. ( which means that the small send and recv buffer size has no effect )
Another approach I took is to use Netty , and set ServerBootstrap.setOption("child.sendBufferSize", 256);, but even this is of not much use. Can anyone help me understand what I am doing wrong /
The buffers have an OS dependent minimium size, this is often around 8 KB.
public static void main(String... args) throws IOException, InterruptedException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.bind(new InetSocketAddress(0)); // open on a random port
InetSocketAddress remote = new InetSocketAddress("localhost", ssc.socket().getLocalPort());
SocketChannel sc = SocketChannel.open(remote);
configure(sc);
SocketChannel accept = ssc.accept();
configure(accept);
ByteBuffer bb = ByteBuffer.allocateDirect(16 * 1024 * 1024);
// write as much as you can
while (sc.write(bb) > 0)
Thread.sleep(1);
System.out.println("The socket write wrote " + bb.position() + " bytes.");
}
private static void configure(SocketChannel socketChannel) throws IOException {
socketChannel.configureBlocking(false);
socketChannel.socket().setSendBufferSize(8);
socketChannel.socket().setReceiveBufferSize(8);
}
on my machine prints
The socket write wrote 32768 bytes.
This is the sum of the send and receive buffers, but I suspect they are both 16 KB
I think Channel.setReadable is what you need. setReadable tell netty temporary pause to read data from system socket in buffer, when the buffer is full, the other end will have to wait.

Rewriting a tcp stream on the fly: how difficult is it? How about taking a dump of said stream?

I'm trying to write a tcp stream 'tunnel' (similar to the ones SSH handles by default) but with one exception, I have to rewrite certain information as it flows through.
I'm certain there's something similar out there but I have not been able to find it.
I have three main questions:
Is there an easy way to save a tcp stream for observation? (ie using netcat, or a ssh -r/-l/-D, or using some other utility alltogether)
how hard is it to rewrite the stream on the fly?
Edit: The information being rewritten would be just the initial authentication.
A straight pass-through tunnel with logging can be cobbled together from existing (or easily found) utilities.
socat -v -x tcp-l:8080,fork,reuseaddr tcp:localhost:80 2>log
In this example, connecting to http://localhost:8080/ will pass through to http://localhost:80/, and log data transferred to log.
The tool TCPreen is specialized for this exact purpose.
If you have root privileges, there are many analyzers such as tcpdump and tcpflow which can capture packets directly from the network, without having to redirect traffic.
socat can also do some very basic stream modification with the ,cr and ,crnl options, which strip/add/replace \r characters.
In any case, back to the original question… It's been ages since I've written any Java, and this is totally untested, but a tunnel that can modify traffic before retransmitting isn't difficult.
public class ForwardAndChangeCaseThread extends Thread {
private Socket in, out;
public ForwardAndChangeCaseThread(Socket in, Socket out) {
this.in = in; this.out = out;
}
public void run() {
byte[] buf = new byte[4096];
InputStream in = this.in.getInputStream();
OutputStream out = this.out.getOutputStream();
int count;
while ((count = in.read(buf)) > 0) {
for (int i = 0; i < count; i++)
if (buf[i] >= 0x40) buf[i] ^= 0x20;
out.write(buf, 0, count);
}
}
}
public class TcpForwarder {
public static void main(String[] args) {
ServerSocket listen = new ServerSocket(8080, 1);
for (;;) {
Socket local = listen.accept();
Socket remote = new Socket("localhost", 80);
new ForwardAndChangeCaseThread(local, remote).start();
new ForwardAndChangeCaseThread(remote, local).start();
}
}
}
Pretty sure Ettercap supports rewriting of TCP streams.
tcpdump can write out packet captures, which you could then later analyze using Wireshark
If you want to do it programmatically, you could inspect their respective sources to get ideas of where to start.
Not to toot my own horn, but I wrote some code to do exactly this in a framework I wrote a long time ago for asynchronous IO. There are a lot of things about the code that are kind of dated now, but it does work. Here's a link to the web page on it:
The StreamModule System
The thing I wrote that does the tunnel thing you want is called PortForward, and there's also something there that will dump out a TCP stream, but I forgot what I called it. They can be easily combined because of how the framework works.
I'll come back if you want help using it to accomplish that goal. As others have pointed out, it is impossible to re-write an SSL stream on the fly. So if your connection is using encryption and/or MACs (one way this would be true is if it were SSL) you're out of luck.
I'm not sure if this is what you are asking, but ...
You cannot rewrite an SSL stream on the fly unless you have the private key for the server's SSL cert ... or you can intercept it at some point (in the client or server address space) where it is not SSL protected. If you could, SSL would be a waste of time.
Similarly, if you capture the entire contents of an SSL stream (in both directions), it will do you no good, unless you have the relevant private keys.

Categories

Resources