Spawning more than 5 client requests on socket - python

If we bind a server socket like this:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(5)
and use something like select() and loop over and over each client connection until the client closes it to exchange messages while the loop (for here) is run concurrently we can make the exchange of server-client messages or client-client exchange concurrent. Can we?
But the problem as I've read is that the server cannot enqueue more than 5 clients to handle one by one;
What methods are there to actually run multiple such server instances, provided the criteris that multiple such server processes start to listen iff the clients queued up reach the level of 5?

When you receive a connection you can either spawn a thread/process to handle that connection.
On the main thread go back to listen for another connection
The 5 bit is the length of the list that are one hold.
Similar to a switchboard operator

The 5 limitation you are concerned about is the size of listener backlog queue. This is how many connections the system will hold in abeyance until it starts rejecting new connections. When you accept a connection room is freed on that queue. So as long as you accept your connections in a timely manner this is not really a concern under normal load conditions. (BTW 5 is on the low side of things. IIR the default max per process on linux, for instance, is 128.)

Probably you misunderstood the function of the backlog argument.
The limit of 5 only applies to connection that are not already accepted.

Related

How does a Python listening socket get setup?

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.
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.

Is it safe to run server.accept() constantly with sockets?

Right now I'm building a server-client program using TCP in Python with the sockets module. Having looked all over the internet, it has become apparent that a conn, addr = server.accept() line is required in the server code, however there is no way for the server to know when the client will connect. It could be from seconds to minutes after the server is run.
So my question is this: can I use threading to constantly run a server.accept() line of code so any client that chooses to connect can? Or could this lead to something malicious connecting?
As per Can 'connect' call on socket return successfully without server calling 'accept'? ,
TCP establishes the connection - the 3-way handshake - under the
covers and puts it in a completed connection queue when it is ready.
Accept() returns the next waiting connection from the front of this
queue.
From the client's perspective it is "connected" but it won't be
talking to anyone until the server accepts and begins processing. Sort
of like when you call a company and are immediately put in the hold
queue. You are "connected" but no business is going to be done until
someone actually picks up and starts talking.
So, you won't "miss" connections if you're not doing that. But accept() is typically run in an infinite loop anyway -- in the main thread or otherwise -- 'cuz it's server's primary job to service clients.
According to Is accept() thread-safe? , accept() is thread-safe, you can very well have it running in a separate thread, or even have multiple accept() calls in different threads (or even different processes in OSes with fork) at the same time.

Detecting when a tcp client is not active for more than 5 seconds

Im trying to make a tcp communication, where the server sends a message every x seconds through a socket, and should stop sending those messages on a certain condition where the client isnt sending any message for 5 seconds.
To be more detailed, the client also sends constant messages which are all ignored by the server on the same socket as above, and can stop sending them at any unknown time. The messages are, for simplicity, used as alive messages to inform the server that the communication is still relevant.
The problem is that if i want to send repeated messages from the server, i cannot allow it to "get busy" and start receiving messages instead, thus i cannot detect when a new messages arrives from the other side and act accordingly.
The problem is independent of the programming language, but to be more specific im using python, and cannot access the code of the client.
Is there any option of receiving and sending messages on a single socket simultaneously?
Thanks!
Option 1
Use two threads, one will write to the socket and the second will read from it.
This works since sockets are full-duplex (allow bi-directional simultaneous access).
Option 2
Use a single thread that manages all keep alives using select.epoll. This way one thread can handle multiple clients. Remember though, that if this isn't the only thread that uses the sockets, you might need to handle thread safety on your own
As discussed in another answer, threads are one common approach. The other approach is to use an event loop and nonblocking I/O. Recent versions of Python (I think starting at 3.4) include a package called asyncio that supports this.
You can call the create_connection method on an event_loop to create an asyncio connection. See this example for a simple server that reads and writes over TCP.
In many cases an event loop can permit higher performance than threads, but it has the disadvantage of requiring most or all of your code to be aware of the event model.

How do I receive and manage multiple TCP connections on the same port?

I have a number of clients who need to connect to a server and maintain the connection for some time (around 4 hours). I don't want to specify a different connection port for each client (as there are potentially many of them) I would like them just to be able to connect to the server on a specific predetermined port e.g., 10800 and have the server accept and maintain the connection but still be able to receive other connections from new clients. Is there a way to do this in Python or do I need to re-think the architecture.
EXTRA CREDIT: A Python snippet of the server code doing this would be amazing!
I don't want to specify a different connection port for each client (as there are potentially many of them)
You don't need that.
I would like them just to be able to connect to the server on a specific predetermined port e.g., 10800 and have the server accept and maintain the connection but still be able to receive other connections from new clients
That's how TCP already works.
Just create a socket listening to port 10800 and accept connections from it.
Use select.select() to detect events on multiple sockets, like incoming connections, incoming data, outgoing buffer capacity and connection errors. You can use this on multiple listening sockets and on established connections from a single thread. Using a websearch, you can surely find example code.

Explain socket buffers please

I was trying to find examples about socket programming and came upon this script:
http://stacklessexamples.googlecode.com/svn/trunk/examples/networking/mud.py
When reading through this script i found this line:
listenSocket.listen(5)
As i understand it - it reads 5 bytes from the buffer and then does stuff with it...
but what happens if more than 5 bytes were sent by the other end?
in the other place of that script it checks input against 4 commands and sees if there is \r\n in the string. dont commands like "look" plus \r\n make up for more than 5 bytes?
Alan
The following is applicable to sockets in general, but it should help answer your specific question about using sockets from Python.
socket.listen() is used on a server socket to listen for incoming connection requests.
The parameter passed to listen is called the backlog and it means how many connections should the socket accept and put in a pending buffer until you finish your call to accept(). That applies to connections that are waiting to connect to your server socket between the time you have called listen() and the time you have finished a matching call to accept().
So, in your example you're setting the backlog to 5 connections.
Note.. if you set your backlog to 5 connections, the following connections (6th, 7th etc.) will be dropped and the connecting socket will receive an error connecting message (something like a "host actively refused the connection" message)
This might help you understand the code: http://www.amk.ca/python/howto/sockets/
The argument 5 to listenSocket.listen isn't the number of bytes to read or buffer, it's the backlog:
socket.listen(backlog)
Listen for connections made to the
socket. The backlog argument specifies
the maximum number of queued
connections and should be at least 1;
the maximum value is system-dependent
(usually 5).

Categories

Resources