Chris
Chris

Reputation: 335

Python socketserver sends FIN-Flag

I implemented the Server-Client example in Python 3.5 from https://docs.python.org/3.5/library/socketserver.html. The Example works for the first message in the loop but the server sends always a FIN-Flag and i don't understand why.

server:

    import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())


if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # Create the server, binding to localhost on port 9999
    server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()

client:

import socket
import sys
import time

HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])

# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    # Connect to server and send data
    sock.connect((HOST, PORT))
    while True:
        print("Try")
        sock.sendall(bytes(data + "\n", "utf-8"))

        # Receive data from the server and shut down
        received = str(sock.recv(1024), "utf-8")
        print("Sent:     {}".format(data))
        print("Received: {}".format(received))
        time.sleep(5)

Wireshark:

17771 12:20:03.585705 127.0.0.1 127.0.0.1 59886   9999 TCP 52 59886 → distinct(9999) [SYN] Seq=0 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
17772 12:20:03.585705 127.0.0.1 127.0.0.1 9999   59886 TCP 52 distinct(9999) → 59886 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
17773 12:20:03.585705 127.0.0.1 127.0.0.1 59886   9999 TCP 40 59886 → distinct(9999) [ACK] Seq=1 Ack=1 Win=8192 Len=0
17774 12:20:03.585705 127.0.0.1 127.0.0.1 59886   9999 TCP 49 59886 → distinct(9999) [PSH, ACK] Seq=1 Ack=1 Win=8192 Len=9
17775 12:20:03.585705 127.0.0.1 127.0.0.1 9999   59886 TCP 40 distinct(9999) → 59886 [ACK] Seq=1 Ack=10 Win=7936 Len=0
17776 12:20:03.585705 127.0.0.1 127.0.0.1 9999   59886 TCP 48 distinct(9999) → 59886 [PSH, ACK] Seq=1 Ack=10 Win=7936 Len=8
17777 12:20:03.585705 127.0.0.1 127.0.0.1 59886   9999 TCP 40 59886 → distinct(9999) [ACK] Seq=10 Ack=9 Win=7936 Len=0
17778 12:20:03.585705 127.0.0.1 127.0.0.1 9999   59886 TCP 48 distinct(9999) → 59886 [PSH, ACK] Seq=9 Ack=10 Win=7936 Len=8
17779 12:20:03.585705 127.0.0.1 127.0.0.1 59886   9999 TCP 40 59886 → distinct(9999) [ACK] Seq=10 Ack=17 Win=7936 Len=0
17780 12:20:03.585705 127.0.0.1 127.0.0.1 9999   59886 TCP 40 distinct(9999) → 59886 [FIN, ACK] Seq=17 Ack=10 Win=7936 Len=0
17781 12:20:03.585705 127.0.0.1 127.0.0.1 59886   9999 TCP 40 59886 → distinct(9999) [ACK] Seq=10 Ack=18 Win=7936 Len=0
17795 12:20:08.588160 127.0.0.1 127.0.0.1 59886   9999 TCP 40 59886 → distinct(9999) [FIN, ACK] Seq=10 Ack=18 Win=7936 Len=0
17796 12:20:08.588160 127.0.0.1 127.0.0.1 9999   59886 TCP 40 distinct(9999) → 59886 [ACK] Seq=18 Ack=11 Win=7936 Len=0

Upvotes: 0

Views: 1946

Answers (1)

CristiFati
CristiFati

Reputation: 41116

It all lies in socketserver.py ([Python]: socketserver — A framework for network servers) and few other places: I'm going to use version 3.5.4 as a reference (doc quotes will be version 3 specific):

  1. BaseServer.serve_forever(self, poll_interval=0.5)(#215) calls _handle_request_noblock(#234):

    self._handle_request_noblock()
    
  2. BaseServer._handle_request_noblock(self)(#306) calls process_request(#313):

    self.process_request(request, client_address)
    
  3. BaseServer.process_request(self, request, client_address)(#335) calls shutdown_request(#342):

    self.shutdown_request(request)
    
  4. TCPServer extends BaseServer(#370):

    class TCPServer(BaseServer):
    
  5. TCPServer overrides shutdown_request(#489):

    def shutdown_request(self, request):
        """Called to shutdown and close an individual request."""
        try:
            #explicitly shutdown.  socket.close() merely releases
            #the socket and waits for GC to perform the actual close.
            request.shutdown(socket.SHUT_WR)
        except OSError:
            pass #some platforms may raise ENOTCONN here
        self.close_request(request)
    
  6. request.shutdown(socket.SHUT_WR)

  1. socket.socket.shutdown is defined in ${PYTHON_SRC_DIR}/Modules/socketmodule.c(#3986):

    static PyObject *
    sock_shutdown(PySocketSockObject *s, PyObject *arg)
    {
        int how;
        int res;
    
        how = _PyLong_AsInt(arg);
        if (how == -1 && PyErr_Occurred())
            return NULL;
        Py_BEGIN_ALLOW_THREADS
        res = shutdown(s->sock_fd, how);
        Py_END_ALLOW_THREADS
        if (res < 0)
            return s->errorhandler();
        Py_INCREF(Py_None);
        return Py_None;
    }
    
  2. As seen, it calls native shutdown API:

    According to the MSDN link above (didn't find official Ux related doc, but I can't say I tried very hard searching):

    If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.

    Note (Ux <-> Win conversion): SHUT_* and SD_* corresponding constants have the same values (e.g. SHUT_WR = SD_SEND = 1)

Upvotes: 1

Related Questions