I noticed that when communicating to a number of UPnP media renderer devices, there was significant latency (2.5 sec per UPnP action) when creating the HTTP socket in HTTPRequest.java. It turned out that when given a host in 'IP notation' (192.168.1.12, for example), the call to the Socket constructor of the form 'sock = new Socket(host, port)' was trying to do a name resolution for the IP address as a side effect of the call (not really necessary). Under Windows XP, with NETBIOS naming service enabled (needed for Windows file sharing), this ends up sending a NETBIOS name request message to the device at the given address. When the device does not support the NETBIOS protocol (most media renderers don't), it takes 2.5 sec for the operation to time out before the Socket constructor proceeds to completion. This latency is big enough to actually stop some media renderers from working properly when sending numerous messages in a sequence.
Here's a patch that gets around the problem by using an alternate form of the Socket constructor in HTTPRequest.java
(modification to the 1.6.2 version)
Inside HTTPRequest.post() method....
if (postSocket == null)
// If host is in IP '.' notation, create a InetAddr here and use
// that to open the socket. This allows the Socket constructor to
// bypass some internal name resolution logic than can introduce
// significant latency (2.5 sec per post request) under Windows
// when TCP/IP NETBIOS name resolution is in effect, and the device
// being contacted doesn't support the NETBIOS protocol (most
// UPnP media renderer devices dont' support NETBIOS name service,
// and it takes 2.5 sec for the Java JVM to timeout waiting for
// a response)
// Split pattern of "\D" below means split when not a digit ('.').
// Helps screen out non-numeric hosts with '.''s
// (e.g. java.sun.com.net).
// I'm guessing this can be done more elegantly...
String hostByteStrings = host.split("\\D");
if( hostByteStrings.length == 4 )
byte hostBytes = new byte;
for( int n = 0 ; n < 4 ; n++ )
hostBytes[n] = (byte)Integer.parseInt( hostByteStrings[n] );
InetAddress inetAddr = InetAddress.getByAddress( host, hostBytes );
postSocket = new Socket( inetAddr, port );
else // not a numeric host address
postSocket = new Socket(host, port);
Thanks for good report anytime :-)
I debate whether to be add your changes, I found the following pages to change the name resolution order.
How to change name resolution order on Windows 95 and Windows NT :
Microsoft Windows XP - DNS and NetBIOS Names :
Could it resolve your problems ?
Hi Skonno -
I looked over the Microsoft links, but I don't think they help with the problem I was trying to solve. I want to set things up so that if a user brings a UPnP media renderer into their house, everything will just work with no changes to their Windows boxes. The only solution I found to bypass the NetBIOS name resolution step for local hosts not in the DNS was to avoid the name resolution processes altogether by modifying the Java code as described.
I'm not saying there isn't a more elegant approach - I agree my fix is a bit of kludge. I do wish Java wouldn't do a name resolution by default in the Socket constructor when a raw IP address is passed though - seems like unnecessary overhead.