Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to reopen a socket?

Tags:

python

sockets

I create many "short-term" sockets in some code that look like that :

nb=1000
for i in range(nb):
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sck.connect((adr, prt)
    sck.send('question %i'%i)
    sck.shutdown(SHUT_WR)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
    sck.close()

This works fine, as long as nb is "small" enough.

As nb might be quite large though, I'd like to do something like this

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.connect((adr, prt)
for i in range(nb):
    reopen(sck) # ? ? ?
    sck.send('question %i'%i)
    sck.shutdown(SHUT_WR)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
sck.close()

So the question is :
Is there any way to "reuse" a socket that has been shutdown ?

like image 896
dugres Avatar asked Sep 11 '09 13:09

dugres


People also ask

What happens when a socket is closed?

close() call shuts down the socket associated with the socket descriptor socket, and frees resources allocated to the socket. If socket refers to an open TCP connection, the connection is closed. If a stream socket is closed when there is input data queued, the TCP connection is reset rather than being cleanly closed.

How do you tell if a socket has been closed?

The most obvious way to accomplish this is having that process call read on the socket for a connection and check whether read returns 0 (i.e. reads zero bytes from the socket), in which case we know that the connection has been closed.

How do you reopen a closed socket in Java?

Once a socket has been closed, it is not available for further networking use (i.e. can't be reconnected or rebound). A new socket needs to be created. Closing this socket will also close the socket's InputStream and OutputStream. If this socket has an associated channel then the channel is closed as well.

What can happen if you do not close a socket when you finish using it?

One way or another, if you don't close a socket, your program will leak a file descriptor. Programs can usually only open a limited number of file descriptors, so if this happens a lot, it may turn into a problem.


2 Answers

No, this is a limitation of the underlying C sockets (and the TCP/IP protocol, for that matter). My question to you is: why are you shutting them down when you can architect your application to use them?

The problem with many short-term sockets is that shutting them down puts them in a state where they cannot be used for a while (basically, twice the packet lifetime, to ensure any packets in the network either arrive and are discarded, or get discarded by the network itself). Basically what happens is that, in the 4-tuple that needs to be unique (source ip, source port, destination ip, destination port), the first one and last two tend to always be the same so, when you run out of source ports, you're hosed.

We've struck this problem in software before where it only became evident when we ran on faster machines (since we could use many more sessions).

Why dont you just open up the socket and continue to use it? It looks like your protocol is a simple request/response one, which should be easily do-able with that approach.

Something like:

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.connect((adr, prt)
for i in range(nb):
    sck.send('question %i'%i)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
sck.close()

Update:

One possibility (and we've done this before) if you're running out of connection due to this continual open/close, is to detect the problem and throttle it. Consider the following code (the stuff I've added is more pseudo-code than Python since I haven't touched Python for quite a while):

for i in range(nb):
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sck.connect((adr, prt)

    while sck.error() == NO_SOCKETS_AVAIL:
        sleep 250 milliseconds
        sck.connect((adr, prt)

    sck.send('question %i'%i)
    sck.shutdown(SHUT_WR)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
    sck.close()

Basically, it lets you run at full speed while there are plenty of resources but slows down when you strike your problem area. This is actually what we did to our product to "fix" the problem of failing when resources got low. We would have re-architected it except for the fact it was a legacy product approaching end of life and we were basically in the fix-at-minimal-cost mode for service.

like image 50
paxdiablo Avatar answered Oct 04 '22 12:10

paxdiablo


I'm not sure what the extra overhead would be like, but you could fully close and reopen the socket. You need to set SO_REUSEADDR, and bind to a specific port you can reuse.

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
like image 24
JimB Avatar answered Oct 04 '22 12:10

JimB