Not trolling, but why use XmlRpc if this is your targetted I/O rate?
You would likely be much better to implement your own socket protocol if
you're expecting this high of socket connections from the client.
XmlRpc (being based on HTTP) is a relatively expensive and slow protocol
to begin with. If you're trying to keep real time game state using
XmlRpc, I'm guessing you'll run into other throughput problems than just
what you've described.
Perhaps you should be looking at using an already existing game engine
that includes sockets. If you don't find anything you like, then
perhaps create a spec and write one for yourself. You might find other
people have a similar problem.
I understand the usefulness of having XmlRpc on the backend, since the
client can be built on any number of platforms, etc. In fact, I have a
game concept that uses XmlRpc because of the non-proprietary nature of
the protocol. But, it sounds like your client is very specific and that
you're going to distribute it. Therefore, it wouldn't be a stretch to
create your own socket protocol, staying away from the stateless types
like http. Keep your connections open, use a connection pool, etc.
I know that doesn't answer your question. It just seems you might need
to step back and rethink your architecture a little. Is XmlRpc really
the right choice for you? Socket programming is not that difficult.
Daniel Kastenholz wrote:
Hi,
I'm writing an online game based on XML-RPC and am currently doing some
performance tests. To measure the throughput, I've written a test case
that attemps to call several remote procedures/methods several thousand
times and takes the time. Now I've stepped over a problem. Everything is
fine when this test is run with a Linux-client/Linux-server setup. But
when I test it with a Windows client, I keep getting BindExceptions
after a short time. 500 iterations are no problem, but once it goes into
thousands, every call results in an exceptions and blocking I/O (about
10 seconds per call!):
<output>
[java] Avoiding obscuring previous error by supressing error
encountered while ending request:
org.apache.xmlrpc.XmlRpcClientException: Exception closing URLConnection
[java] java.net.BindException: Address already in use: connect
</output>
I've searched a little and learned that this problem is kind of
Windows-homebrewn:
<quote src="http://lists.mysql.com/java/5132">
[...] Windows XP only will make outbound TCP/IP connections using ports
1024-5000, and takes up to 4 minutes to recycle them :(
Therefore, if you do a lot of connections in a short amount of time, you
can easily eat that port range up (That 3960 is awful close to 5000 -
1024, isn't it :p ).
The range can be adjusted via a registry setting (yes the KB article
says Windows 2000, but it works on XP as well, I've tested it), see:
http://support.microsoft.com/default.aspx?scid=kb;en-us;196271
</quote>
But this isn't really an option, because I don't want players to have to
change their registry settings before being able to play the game
without a crash every couple of minutes. Changing XMLRPC's
"setKeepAlive()" option didn't help, either. The Sun people suggest yet
another workaround:
<quote src="http://java.sun.com/features/2002/08/j2se-network.html">
With both TCP and UDP, it may be necessary at times to bind more than
one socket to the same socket address. In J2SE 1.4, the SO_REUSEADDR
socket option can be enabled or disabled using the
ServerSocket.setReuseAddress method for TCP sockets and the
DatagramSocket.setReuseAddress method for UDP sockets.
In the case of TCP, when a connection is closed it may remain in a
timeout state for a short period of time. In such cases, it is not
possible to bind a socket to the required address if a previous
connection to the same address is in a timeout state; typically, you get
an error message "Couldn't bind, address already in use". If you wish to
allow the socket to be bound even though a previous connection is in a
timeout state, use setReuseAddress prior to binding (using bind) the
socket. It's worth noting that when a ServerSocket is created, the
initial setting of SO_REUSEADDR is not defined. Use getReuseAddress to
determine the setting of SO_REUSEADDR. Also, after a socket is bound,
the behavior of SO_REUSEADDR is not defined.
In the case of UDP, it may be necessary to bind more than one socket to
the same socket address for the purpose of receiving multicast packets.
The SO_REUSEADDR socket option allows multiple sockets to be bound to
the same socket address if it is enabled prior to binding the socket.
Unlike with TCP sockets, when a DatagramSocket is created, the initial
setting of SO_REUSEADDR is disabled; however, after a socket is bound,
the behavior of SO_REUSEADDR is not defined.
</quote>
Currently, this seems to be the only solution without accessing the
registry. Unfortunately, I wouldn't know where to set this flag. The
only connection-related code that I could find in the sources was a
".getFile()" call that is made on an URL object. Besides, I wouldn't
like to hack around in the code of the XMLRPC distribution, as this
would complicate upgrading.
Any suggestions or workarounds?
Thank you very much.
Daniel