Python Binding Socket: “Address already in use”, after closing socket - python

I know there is a similar question already, but none of the solutions solve my problem. Over ssh I am starting a script on a remote client with
nohup python script.py &
This script contains the following:
TCP_PORT = 5005
host = ""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.settimeout(40)
s.bind((host, TCP_PORT))
s.listen(0)
c, addr = s.accept()
...some code...
try:
while True:
c.send(str(1).ljust(16).encode())
except Exception as e:
print("exiting main")
print(e)
c.close()
s.close()
When I run the code two times in e row, the second time I always get the above mentioned error. The log of the python output:
exiting main
[Errno 32] Broken pipe
Traceback (most recent call last):
File "LogImages.py", line 204, in <module>
main(interv)
File "LogImages.py", line 114, in main
s.bind((host, TCP_PORT))
OSError: [Errno 98] Address already in use
So obviously the process calls c.close() and s.close(). So how can the address still be in use?

Closing a socket just releases the handle to any underlying connection. It can still take the implementation some amount of time to complete the orderly shutdown of the connection and, during that time, the address is still in use.
For example, if you have an active connection and the other side isn't reading from it, the implementation will give it time to read the data that was sent. During that time, the address is still in use.

Related

"[Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted" after closing and reopening Python socket

I have this code:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind(('10.0.0.253', 8080))
except:
s.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('10.0.0.253', 8080))
s.listen(1)
conn, addr = s.accept()
which binds, then if it encounters an error with that, destroys the socket then creates a new one and binds it to the same IP and port. For some reason, even after closing the socket, I get this error:
Traceback (most recent call last):
File "C:\Users\other\Desktop\tcpReverseShell_Server.py", line 68, in <module>
main()
File "C:\Users\other\Desktop\tcpReverseShell_Server.py", line 66, in main
connect()
File "C:\Users\other\Desktop\tcpReverseShell_Server.py", line 43, in connect
s.bind(('10.0.0.253', 8080))
File "C:\Python27\lib\socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
error: [Errno 10048] Only one usage of each socket address (protocol/network
address/port) is normally permitted
The only solution I've found is to use s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1), but when I try that I get this error: [Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions. I
I am on Windows 10, Python 2.7.13.
I can simulate your problem by running the python script twice concurrently. The problem is that some other application is currently also using the socket.
In your code, the except block is triggered when your socket fails to bind. However, when you try to .close() the socket and try again, it does nothing as it is trying to .close() an unbound socket. Hence, your code is equivalent to:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('10.0.0.253', 8080))
s.listen(1)
conn, addr = s.accept()
Note that when you .close() the socket, it also does not .close() the currently bound application, it attempts to .close() to socket object you created. So, trying to bind the socket again will fail.
To find out what is using the socket, you can use netstat:
netstat -aon | findstr :8080
This should give you something like:
TCP 127.0.0.1:8080 0.0.0.0:0 LISTENING 6604
Then, if you want to kill it forcefully, you can use TaskKill and the application's PID:
TaskKill /PID 6604 /F

How to connect() with a non-blocking socket?

In Python, I would like to use socket.connect() on a socket that I have set to non-blocking. When I try to do this, the method always throws a BlockingIOError. When I ignore the error (as below) the program executes as expected. When I set the socket to non-blocking after it is connected, there are no errors. When I use select.select() to ensure the socket is readable or writable, I still get the error.
testserver.py
import socket
import select
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
host = socket.gethostname()
port = 1234
sock.bind((host, port))
sock.listen(5)
while True:
select.select([sock], [], [])
con, addr = sock.accept()
message = con.recv(1024).decode('UTF-8')
print(message)
testclient.py
import socket
import select
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
host = socket.gethostname()
port = 1234
try:
sock.connect((host, port))
except BlockingIOError as e:
print("BlockingIOError")
msg = "--> From the client\n"
select.select([], [sock], [])
if sock.send(bytes(msg, 'UTF-8')) == len(msg):
print("sent ", repr(msg), " successfully.")
sock.close()
terminal 1
$ python testserver.py
--> From the client
terminal 2
$ python testclient.py
BlockingIOError
sent '--> From the client\n' successfully.
This code works correctly except for the BlockingIOError on the first connect(). The documentation for the error reads like this: Raised when an operation would block on an object (e.g. socket) set for non-blocking operation.
How do I properly connect() with a socket set to non-blocking? Can I make connect() non-blocking? Or is it appropriate to just ignore the error?
When using socket.connect with a non-blocking socket, it is somewhat expected to get a BlockingIOError at first. See TCP Connect error 115 Operation in Progress What is the Cause? for an explanation of the cause. Basically, the socket isn't ready yet and raises BlockingIOError: [Errno 115] Operation now in progress, also known as EINPROGRESS.
The solution is to either catch and ignore the exception or to use socket.connect_ex instead of socket.connect because that method doesn't raise an exception. Especially note the last sentence from its description in the Python docs:
socket.connect_ex(address)
Like connect(address), but return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as “host not found,” can still raise exceptions). The error indicator is 0 if the operation succeeded, otherwise the value of the errno variable. This is useful to support, for example, asynchronous connects.
Source: https://docs.python.org/3/library/socket.html#socket.socket.connect_ex
If you want to keep using socket.connect, you can catch and ignore the responsible EINPROGRESS error:
>>> import socket
>>>
>>> # bad
>>> s = socket.socket()
>>> s.setblocking(False)
>>> s.connect(("127.0.0.1", 8080))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
BlockingIOError: [Errno 115] Operation now in progress
>>>
>>> # good
>>> s = socket.socket()
>>> s.setblocking(False)
>>> try:
... s.connect(("127.0.0.1", 8080))
... except OSError as exc:
... if exc.errno != 115: # EINPROGRESS
... raise
...
>>>
The trick here is that when the select completes the first time, then you need to call sock.connect again. The socket is not connected until you have received a successful return status from connect.
Just add these two lines after the first call to select completes:
print("first select completed")
sock.connect((host, port))
EDIT:
Followup. I was wrong to have stated that an additional call to sock.connect is required. It is however a good way to discover whether the original non-blocking call to connect succeeded if you wish to handle the connection failure in its own code path.
The traditional way of achieving this in C code is explained here: Async connect and disconnect with epoll (Linux)
This involves calling getsockopt. You can do this in python too but the result you get back from sock.getsockopt is a bytes object. And if it represents a failure, you then need to convert it into an integer errno value and map that to a string (or exception or whatever you require to communicate the issue to the outside world). Calling sock.connect again maps the errno value to an appropriate exception already.
Solution 2:
You can also simply defer calling sock.setblocking(0) until after the connect has completed.

Python server-client

I need some help. I have a simple server:
host="localhost"
port=4447
from socket import *
import thread
def func():
while 1:
data = conn.recv(1024)
if not data:
continue
else:
print("%s said: %s")%(player, data)
conn.close()
s=socket(AF_INET, SOCK_STREAM)
s.bind((host,port))
s.listen(2)
print("Waiting for clients on localhost, port %s")%port
while 1:
conn, addr = s.accept()
player = addr[1]
print(conn)
thread.start_new_thread(func,())
And a simple client:
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 4447
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
while 1:
data = raw_input("Input: ")
s.send(data)
So when I connect to the server I can type anything and it is printed in the server's terminal. When I open another terminal and start second client I can also type anything and it is sent to the server, but when I go back to the first client's terminal and type several messages, it returns:
Traceback (most recent call last):
File "Client.py", line 18, in <module>
s.send(data)
socket.error: [Errno 32] Broken pipe
So I fixed that with adding conn as a parameter in func(), but I don't understand why this error happened? Could anyone please explain it to me?
Thanks!
Your func, apart from needing a better name, uses global state in your program to communicate with a client. No matter how many threads you start to handle client connections, there's still only one global conn variable. Each time a new client connects, your main thread loop rebinds conn to the new connection. The old socket is thrown away and automatically closed by the Python runtime.
You can fix this by removing the use of global variables to track per-connection state. A better route to explore, though, is Twisted.

Python client / server question

I'm working on a bit of a project in python. I have a client and a server. The server listens for connections and once a connection is received it waits for input from the client. The idea is that the client can connect to the server and execute system commands such as ls and cat. This is my server code:
import sys, os, socket
host = ''
port = 50105
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("Server started on port: ", port)
s.listen(5)
print("Server listening\n")
conn, addr = s.accept()
print 'New connection from ', addr
while (1):
rc = conn.recv(5)
pipe = os.popen(rc)
rl = pipe.readlines()
file = conn.makefile('w', 0)
file.writelines(rl[:-1])
file.close()
conn.close()
And this is my client code:
import sys, socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = 'localhost'
port = input('Port: ')
s.connect((host, port))
cmd = raw_input('$ ')
s.send(cmd)
file = s.makefile('r', 0)
sys.stdout.writelines(file.readlines())
When I start the server I get the right output, saying the server is listening. But when I connect with my client and type a command the server exits with this error:
Traceback (most recent call last):
File "server.py", line 21, in <module>
rc = conn.recv(2)
File "/usr/lib/python2.6/socket.py", line 165, in _dummy
raise error(EBADF, 'Bad file descriptor')
socket.error: [Errno 9] Bad file descriptor
On the client side, I get the output of ls but the server gets screwed up.
Your code calls conn.close() and then loops back around to conn.recv(), but conn is already closed.
If you want your client to repeat what it's doing, just add a loop in there ;)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = 'localhost'
port = input('Port: ')
s.connect((host, port))
while True:
cmd = raw_input('$ ')
s.send(cmd)
file = s.makefile('r', 0)
sys.stdout.writelines(file.readlines())
Should probably be closer to what you want.
Other comments:
s.listen(1)
This statement should probably be moved outside of the while loop. You only need to call listen once.
pipe = os.popen(rc)
os.popen has been deprecated, use the subprocess module instead.
file = s.makefile('r', 0)
You're opening a file, yet you never close the file. You should probably add a file.close() after your sys.stdout.writelines() call.
EDIT: to answer below comment; done here due to length and formatting
As it stands, you read from the socket once, and then immediately close it. Thus, when the client goes to send the next command, it sees that the server closed the socket and indicates an error.
The solution is to change your server code so that it can handle receiving multiple commands. Note that this is solved by introducing another loop.
You need to wrap
rc = conn.recv(2)
pipe = os.popen(rc)
rl = pipe.readlines()
fl = conn.makefile('w', 0)
fl.writelines(rl[:-1])
in another while True: loop so that it repeats until the client disconnects, and then wrap that in a try-except block that catches the IOError that is thrown by conn.recv() when the client disconnects.
the try-except block should look like
try:
# the described above loop goes here
except IOError:
conn.close()
# execution continues on...

Python socket error occured

I wrote this code.
import socket
host = 'localhost'
port = 3794
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((host, port))
while 1:
print 'Type message you want to send...'
msg = raw_input()
if msg == '':
s.close()
break
s.sendall(msg)
and next execute this code.
Traceback (most recent call last):
File "socket.py", line 11, in ?
s.bind((host, port))
File "<string>", line 1, in bind
socket.error: (99, 'Cannot assign requested address')
What's wrong?
Do you know solutions?
This means that you already have a socket bound to 3794 port.
It may be another application or it means that port didn't got released yet after the previous run of your own script (it happens, if script terminated improperly).
Simply try to use another port number - I believe everything will work fine.
I had this same problem and it was caused by trying to listen on the wrong host. When I changed it to an IP that was actually associated with the machine the code was running on (localhost), the problem went away.
This error comes up mostly due to the the port being already used by another application/service .
Choose a port number above the range of registered ports , i.e 49151

Categories

Resources