Simulate back pressure in TCP send

Go To StackoverFlow.com

5

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 /

2012-04-04 16:44
by Bhaskar


3

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

2012-04-04 17:24
by Peter Lawrey
I checked with Socket.getSendBufferSize() ( also for Receive ) just before I start sending and receiving - it definitely says 256. Does it still mean that the actual buffer size is not 256 bytes - Bhaskar 2012-04-05 10:16
I suspect not, you should be able to test how large it actually is. Send data until you can't send any more - Peter Lawrey 2012-04-05 11:19
Old comment, but I just wanted to chime in. It's no so much OS dependent as it is settings dependent, for instance in many Linux distros(CentOS, RHEL) the default average size for net.ipv4.tcp_wmem is 16kb, which is what you are seeing here. Here is my out of the box CentOS 5 config:

net.ipv4.tcp_wmem = 4096 16384 4194304 Setting the setSendBufferSize to less than the min(4096) will result in it using the average(16k). If you want really small buffers you will have to change this, but usual caveat can break your system in unexpected ways blah blah blah - user439407 2012-09-20 07:25

@user439407 You are right that it can be changed. From a Java point of view, its not something you would change often. The default value and which values it can be usefully changed to depend on the OS - Peter Lawrey 2012-09-20 07:30


4

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.

2012-04-04 17:24
by secmask
Ads