Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a Python listening socket get setup?

Tags:

python

sockets

When you setup a simple TCP listening socket using the Python 'socket' module, what are the different steps involved doing?

The code I'm talking about looks like this:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 50000))
s.listen(1)
conn, addr = s.accept()

The s = ... seems pretty straightforward - you are expressing your intent to create an ipv4 TCP socket, without having done anything yet.

What I'm curious about is this:

  • What does it mean to bind to a socket, without listening?
  • How does limiting the number of unaccepted connections using listen(n) work?
    • If you have listen(1), you're in the middle of dealing with the first connection you accepted, and a second client tries to connect, is the second client waiting for the SYN-ACK? Or does the 3 way handshake happen, and he's waiting for actual data?
    • What happens if a third client tries to connect - does he immediately get a TCP RST?
    • Does setting the number of unaccepted connections here set some option in the kernel to indicate how many connections it should accept? Or is this all handled in Python?
  • How can you be listening without accepting? What does it mean to accept a connection?

Every article I've come across seems to just assume these steps make sense to everyone, without explaining what exactly it is that each one does. They just use generic terms like

listen() starts listening for connections

bind() binds to a socket

accept() just accepts the connection

Defining a word by using that word in the definition is kind of a dumb way to explain something.

like image 759
John Avatar asked Nov 17 '25 06:11

John


1 Answers

it's basically a 1-to-1 from the POSIX c calls and as such I'm including links to the man pages, so that you can read their explanation and corresponding c code:

socket creates a communication endpoint by means of a file-descriptor in the namespace of the address-family you specified but assigns neither address nor port.

bind assigns an address and port to said socket, a port which may be chosen randomly if you request a port for which you do not have the privilige. (like < 1024 for non-root user)

listen makes the specific socket and hence address and port a passive one, meaning that it will accept incoming connections with the accept call. To handle multiple connections one after the other, you get to specify a backlog containing them, connections that arrive while you're handling one get appended. Once the backlog is full, the system will respond as such to those systems with an approach that makes them reconnect by withholding SYN, withholding ACK response etc..

As usual you can find someone explaining the previous to you a lot better.

accept then creates a new non-listening socket associated with a new file descriptor that you then use for communication with said connecting party. accept also works as a director for your flow of execution, effectively blocking further progress until a connection is actually available in the queue for it to take, like a spinlock. The only way around that is to declare the socket non-blocking in which case it would return immediately with an error.

like image 104
Harald Brinkhof Avatar answered Nov 19 '25 20:11

Harald Brinkhof



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!