Alan, you got me.

> So, in order to get your code working, I had to assign an explicit port number, e.g. 8888. Then your code runs as expected.

That is the kind of thing I did,sorry I didn't paste it in (I thought it might have been something I was doing wrong.)
However, if you limit the memory using -Xmx to something like 40m you would see an out of memory error sooner.
My applications that use it tend to run out of memory after about a day using 128m memory limit.

> I do not know why this is yet, and will be investigating.

Let me know if and when you would like me to test anything out!

Regards,

Gareth


On 1 October 2010 20:36, Alan Kennedy <report@bugs.jython.org> wrote:

Alan Kennedy <jython-dev@xhaus.com> added the comment:

The attached code should not run. Instead, it should crash. On Windows, it does so with a socket.error, "Address already in use".

The reason for this is because of the deferred way that socket objects are created in jython. Java has different objects for Client (java.net.Socket+java.nio.channels.SocketChannel) and Server (java.net.ServerSocket+java.nio.channels.ServerSocketChannel) objects. Jython cannot know whether to create a client or serever socket until some client or server specific behaviour is observed. For clients, this is a connect() call, and for servers, this is a listen() call. When a connect() is made, jython then knows to create a java.net.Socket+java.nio.channels.SocketChannel to implement the socket. Similarly, when a listen() call is made, jython then knows to create a java.net.ServerSocket+java.nio.channels.ServerSocketChannel to implement the socket. Any attempt to get information about a socket before either a connect() or listen() call is made, i.e. before the implementation socket is created, will fail, although attempts are made to return already set configuration values, if possible.

But the default TCPServer code from SocketServer.py is not aware of this subtlety of jython sockets. The following methods illustrate the issue (comments snipped to make the code smaller).

class TCPServer(BaseServer):

   def __init__(self, server_address, RequestHandlerClass):
       BaseServer.__init__(self, server_address, RequestHandlerClass)
       self.socket = socket.socket(self.address_family,
                                   self.socket_type)
       self.server_bind()
       self.server_activate()

   def server_bind(self):
       if self.allow_reuse_address:
           self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
       self.socket.bind(self.server_address)
       self.server_address = self.socket.getsockname()

   def server_activate(self):
       self.socket.listen(self.request_queue_size)

Note that the server_address is set before after the bind() call, but before the listen() call. Meaning self.socket.getsockname() will return 0 for the port number, which was the requested value. The actual ephemeral port number wll not be assigned until after the listen() call.

So, in your attached code, the (host, port) tuple ("localhost", 0) will be returned for server_address, which is not a valid socket address for the client to connect to. As I mentioned, on Windows this crashes with an "Address already in use" exception.

So, in order to get your code working, I had to assign an explicit port number, e.g. 8888. Then your code runs as expected.

Notes:

1. The above is really a bug in the jython implementation of SocketServer.TCPServer, which we took directly from cpython without modification. Our implementation needs to be aware of the deferred creation issues mentioned above. I'm surprised if it runs on any platform, i.e. no platform should permit an attempt to connect port 0.

2. Once the code is running, by specifying an explicit port number, it does seem to slowly consume memory. In 30 mins of running, it seems to have consumed about 15M of memory. I do not know why this is yet, and will be investigating.

----------
nosy: +amak

_______________________________________
Jython tracker <report@bugs.jython.org>
<http://bugs.jython.org/issue1660>
_______________________________________