2017-10-17 9 views
0

J'ai implémenté l'exemple Serveur-Client dans Python 3.5 de https://docs.python.org/3.5/library/socketserver.html. L'exemple fonctionne pour le premier message de la boucle mais le serveur envoie toujours un drapeau FIN et je ne comprends pas pourquoi.Socketserver Python envoie FIN-Flag

serveur:

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 
+0

La méthode 'handle' de votre serveur lit le client et envoie un message Et puis c'est fini. Ce "fait" signifie que la connexion TCP se ferme ce qui est fait en envoyant un FIN. Ainsi, cela fonctionne comme implémenté qui pourrait ou non être ce que vous voulez. Cela aurait peut-être été utile si vous aviez documenté ce que vous attendiez de votre code au lieu de simplement se plaindre qu'il fait la mauvaise chose. –

Répondre

0

Tout se trouve dans socketserver.py ([Python]: socketserver — A framework for network servers) et quelques autres endroits: I m va utiliser la version 3.5. 4 comme référence (citations doc sera la version spécifique):

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

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

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

    self.shutdown_request(request) 
    
  4. TCPServer étend 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 est défini dans $ {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. Comme on le voit, il appelle natif shutdownAPI:

    Selon le MSDN lien ci-dessus (n'a pas trouvé officiel Ux doc connexes, mais je ne peux pas dire que j'ai essayé de chercher très dur):

    Si le paramètre comment est SD_SEND, les appels suivants à la fonction send ne sont pas autorisés. Pour les sockets TCP, un FIN sera envoyé après que toutes les données ont été envoyées et acquittées par le destinataire.

    Remarque (Ux < ->Win de conversion): SHUT_ * et SD_ * constantes correspondantes ont les mêmes valeurs (par exemple SHUT_WR = SD_SEND = 1)

+0

Est-ce que cela répond à votre question? – CristiFati