JDK-8286627 : Socket setSendBufferSize() does not work
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 8,11,17,18,19
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2022-05-08
  • Updated: 2022-05-13
  • Resolved: 2022-05-12
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Windows 10 Pro
Java 17

A DESCRIPTION OF THE PROBLEM :
Socket sendBufferSize() [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/net/Socket.html?msclkid=4a181c0cceb311eca185e976544434c5#setSendBufferSize(int)] should limit the number of bytes sent to the server. Its value can decrease based on the receive buffer of the other end but should never increase beyond its own value 

If Server advertises an Receive Buffer Window [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/net/Socket.html?msclkid=4a181c0cceb311eca185e976544434c5#setReceiveBufferSize(int)] of size 30 bytes and the client has an Send Buffer Window of only 10 bytes the client should only send 10 bytes of data with each packet as it is capable of only that much. 

But instead it ignores this setting and sends 30 bytes of data in each packet regardless i.e it adjusts according to the server  settings

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Run an server socket on an separate process[JVM] and set its receiveBufferSize() before calling accept() to an value of 30

2) Run the client on an separate process[JVM] and sets its sendBufferSize() to 10. In the client code and in the server code i have set this value 3 times but it didn't make a difference

3) a) Open wire shark 

   b)  Select the capture option as Adapter for loop back traffic capture

   c)  Set the display filter as  tcp.dstport==2500 [packets going to port 2500]

   d) Run the capture process and wait

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
As the client socket is only capable of sending 10 bytes it should send 10 packets each of size 10 bytes
ACTUAL -
Client sends 4 packets 3 packets each of size 30 bytes and the last packet of size 10 bytes. Send Buffer Setting is ignored

Wire shark Log[Data is sent from packet 9 onwards]

No.     Time           Source                Destination           Protocol Length Info
6      11.966141      192.168.1.2           192.168.1.2           TCP      56     60151 → 2500 [SYN] Seq=0 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1

No.     Time           Source                Destination           Protocol Length Info
8      11.966328      192.168.1.2           192.168.1.2           TCP      44     60151 → 2500 [ACK] Seq=1 Ack=1 Win=2619648 Len=0

No.     Time           Source                Destination           Protocol Length Info
9      11.967784      192.168.1.2           192.168.1.2           TCP      74     [TCP Window Full] 60151 → 2500 [ACK] Seq=1 Ack=1 Win=2619648 Len=30


No.     Time           Source                Destination           Protocol Length Info
11     11.967852      192.168.1.2           192.168.1.2           TCP      74     [TCP Window Full] 60151 → 2500 [ACK] Seq=31 Ack=1 Win=2619648 Len=30

No.     Time           Source                Destination           Protocol Length Info
13    11.967888      192.168.1.2           192.168.1.2           TCP      74     [TCP Window Full] 60151 → 2500 [ACK] Seq=61 Ack=1 Win=2619648 Len=30

No.     Time           Source                Destination           Protocol Length Info
15     11.967921      192.168.1.2           192.168.1.2           TCP      54     60151 → 2500 [PSH, ACK] Seq=91 Ack=1 Win=2619648 Len=10

Upon checking the size of the send buffer on the client it  prints 10 but it sends 30 bytes

---------- BEGIN SOURCE ----------
Server. Run as a separate process[JVM]

public static void main(String[] args)throws Exception
 {
  try(ServerSocket server=new ServerSocket())
  {
  //tells client able to receive only 30 bytes
   server.setReceiveBufferSize(30); 
   server.setReuseAddress(true);
   server.bind(new InetSocketAddress(InetAddress.getLocalHost(),2500));
  
   int length;
   byte[] data=new byte[100];
   while(true)
   {
    try(Socket client=server.accept())
    { 
    //here as well setting the client send buffer to 10 in an last attempt to make it send 10 bytes
     client.setSendBufferSize(10);
     try(InputStream input=client.getInputStream())
     {
      while((length=input.read(data))>0)
      {
       System.out.println(Arrays.toString(Arrays.copyOfRange(data,0,length)));
       System.out.println("============");
      } 
     }     
    } 
   }   
  } 
 }

Client run as an separate process[JVM]

public static void main(String[] args)throws Exception
 {
  try(Socket client=new Socket())
  {
  //Set send buffer size before connecting
   client.setSendBufferSize(10);
   
   client.connect(new InetSocketAddress(InetAddress.getLocalHost(),2500));
  
   byte[] data=new byte[100];
   for(int i=0;i<data.length;i++){data[i]=(byte)i;} 
   
   //set send buffer size one more time after connecting
   client.setSendBufferSize(10);
   
   //Verifying send buffer is actually 10. It is
   System.out.println(client.getSendBufferSize());
   
   try(OutputStream output=client.getOutputStream())
   {
    output.write(data);
   }  
  }
 }

Still sends 30 bytes of data even after setting it to 10 in 3 places[twice on the client side and one more time on the server side]
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround

FREQUENCY : always



Comments
From https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/net/StandardSocketOptions.html#SO_SNDBUF "The value of the socket option is a hint to the implementation to size the buffer and the actual size may differ"
12-05-2022

As the documentation says, the buffer sizes are only a hint for the operating system. And even if the hint is honored, it doesn't guarantee that the OS will actually limit its sending to the configured buffer.
12-05-2022

Run Wireshark and use Adapter for loopback traffic capture Set the filter as tcp.dstport == 2500 The observations on Windows 10: JDK 8: Failed, Len = 50 JDK 11: Failed. JDK 17: Failed. JDK 18: Failed. JDK 19ea+3: Failed.
12-05-2022

Requested the submitter provide the details of using Wire shark to capture the data.
10-05-2022