Python: asynchronous tcp socketserver - python

I'm looking http://docs.python.org/library/socketserver.html to try and handle asynchronous requests with the socketserver in python. At the very bottom there is an example, but it doesn't make sense. It says you use port 0 which assigns an arbitrary unused port. But how do you know what port to use for the client if they are not in the same program? I do not quite understand how to make this useful.

Since the client is implemented in the same script as the server, the port is known. In a real-world scenario, you should specify a port for your daemon. Besides letting your clients know on which port to connect, you may also need to know so that you can open firewalls between your clients and your server.

In the example you linked, they are fetching the port:
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
However, you should really be looking at www.twistedmatrix.com if you are serious about writing async handling :)

You need to retrieve the port that was assigned to the socketserver once the bind is done: in this case, this will probably be through ip, port = server.server_address.
The arbitrary port is just if you want to create a server without specifying a port: the OS will assign an available port.
Of course there must also be a way to specify which port to bind to.

server = ThreadedTCPServer((HOST, 0), ThreadedTCPRequestHandler)
ip, port = server.server_address
...
client(ip, port, "Hello World 1")
The PORT value 0 says "I don't care what port number it is," so the server_address's port value is assigned by the ThreadedTCPServer() call. It is not zero. Later, you pass that port value to the client, who uses it.

Related

Find OS generated port before using socket.connect() in Python

I would like to ask if there any way to to create a socket in Python, using:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
And then, extract the port which going to be generated by the OS, before using:
sock.connect((SERVER_IP, SERVER_PORT)
i.e. my goal is to find the source port of the first SYN packet which will be sent to the server, as part of the 3-way handshake, before actually executing the 3-way handshake.
Note: I figured out that finding out the generated port is possible using:
generated_port = sock.getsockname()[1]
But, unfortunately, the value of generated_port is set just after using sock.connect().
Any help will be much appreciated!
The local port is only available after the socket is bound to a local IP and port. If not explicitly done by calling bind this will be implicitly done doing connect. Therefore to get the local port before calling connect one has to explicitly call bind before that:
import socket
s = socket.socket()
s.bind(('0.0.0.0',0))
print(s.getsockname()[1])
s.connect((host,port))

(Python/TFTP-Server) how to listen to an non (yet) existing IP-address (RNDIS)?

Hy folks,
my problem: I want to start a (tftp) server for an non-existing IP-address.
the server is meant for USB/RNDIS where its IP-address by nature only is existing when there is actual network-traffic going on -- but I want to start the server 'early' (e.g. when Windows starts).
idea was to bind() the socket to 0.0.0.0 - and then to check each request for "valid" addresses.
problem with that approach: recfrom() only returns the source-address (client), but not the destination (server)!
how do I get the IP-address this client has talked to?
(I could of course check for the same subnet at least, but I need the real server-address this client was talking to!)
or, are there by chance any options to let bind() use a non-existing IP-address?
cheers.
p.s.
this is for the Python tftpy server...
-- at the moment I need to ping from client side when starting the server, which is quite meh...
There's no way to get the local address directly but there's a trick that will usually work for you.
Let's say that you just obtained a buffer and client address from recvfrom. Now you create a new auxiliary UDP socket, connect it to the client's address, and then use getsockname to obtain the local address on this new socket. (With UDP, connect doesn't actually send anything to the peer, it just does address resolution.)
So in this way, you can discover the IP address that the server system would use as source were it to send a datagram back to the client system. That's usually the same address that the client used to target the server.
>>> cbytes, caddr = server_sock.recvfrom(2048)
>>> print(caddr) # Client IP and port
('192.168.0.11', 38869)
>>> aux_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> aux_socket.connect((caddr[0], 9999)) # Connect back to client (port doesn't matter)
>>> saddr = aux_socket.getsockname() # Get local IP and port (ignore port here too)
>>> print(saddr)
('192.168.0.12', 39753)
This works on linux. I'm not 100% sure it would work the same way on Windows but it seems reasonable to expect that it would.

Python socket NAT port address

I have a client socket behind a NAT and I want to get the local port number used by the process.
To illustrate my question, here's a quick example.
Let's say I create a server using the following code:
welcome_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
welcome_socket.bind(("", 1500))
welcome_socket.listen(5)
I then listen for incoming connections:
(client_socket, address) = self.welcome_socket.accept()
I connect from a client (behind a NAT) using the following code:
sock = socket.create_connection(("server_address", 1500))
Here is where I'm a little confused.
The address I get on the server side has the public address of the WiFi network the client is connected to (which I expect) and some port number, which based on my understanding of NATs, should be different from the actual port number used by the client and is used for address translation.
However, if I used the getsockname() function on the client, I get the same port number as the one given by the server.
Returning to the example in code.
On the server:
client_socket.getpeername()
>>> ('WiFi_address', 4551)
On the client:
sock.getsockname()
>>> ('local_address', 4551)
So, both port numbers are the same, even though the client is behind a NAT. How is this the case? Am I misunderstanding how the NAT works? Or is there another command to get the physical address that the client socket is bound to?
Any insight would be appreciated.
It is likely that the Router is using Port Address Translation (or one-to-many NAT). The wiki link further quotes
PAT attempts to preserve the original source port. If this source port
is already used, PAT assigns the first available port number starting
from the beginning of the appropriate port group 0-511, 512-1023, or
1024-65535. When there are no more ports available and there is more
than one external IP address configured, PAT moves to the next IP
address to try to allocate the original source port again. This
process continues until it runs out of available ports and external IP
addresses.
And that should be the reason why you are seeing port 4551 on the server.
(This link should also help to clarify the difference between NAT and PAT)

Python socket not accepting external connections

I have a python socket that is supposed to be listening to all incoming sockets on port 2022 and I have port forwarding enabled as well as a dynamic DNS service. When I am connected to the same network and I try to connect to my pc using the pc's IP address it works like a charm but when I try to use the public IP of my network it won't work although I have done proper port forwarding. Here is my code, it stucks on the last line and doesn't accept any connections outside the network:
IPC= '0.0.0.0'
PORTC =2022
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.bind((IPC,PORTC))
client_socket.listen(5)
connection =client_socket.accept()[0].makefile('wb')
If you can connect from a different PC inside your private network, then there's nothing wrong with your Python code. It's almost certain that there's something wrong with your router or the port forwarding config.
Make sure that you've re-reviewed your port forwarding settings and perhaps try restarting the router (be careful to verify your internally assigned IP addresses haven't changed if you go this route).

Python Socket Port Use

I'm trying to set a server application and client application in which the server will listen for connections using localhost and a certain port - however - if for example, the port is 2001 - if that port is not available, I would like to use 2002, if that's not available then 2003 - etc. How do I implement that in my code?
example = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
example.bind(("localhost",2001))
may be just loop around till it doesnt generate an exception
port = 2001
while True:
try:
example.bind(("localhost",port))
except:
port += 1
continue
break
Rather than try to find an available free port in some kind of loop you can bind to port 0 (zero) and let your OS bind to a suitable free port. You can then access the bound port via introspecting the server socket object using socket.getsockname()
I prefer to bind the socket to a random port number assigned by the kernel and then query for the port number opened.
example.bind((host,0)) #0-random, free port number
example.getsockname()

Categories