Cintes transportadores

En un centre de distribució automatitzat, disposem de desenes de cintes transportadores que informen del seu estat de funcionament (velocitat i alertes) a un servidor mitjançant connexions TCP asíncrones.

Servidor bàsic

Per tal d’implementar un servidor bàsic que gestioni les connexions d’un conjunt de cintes, fes el següent:

  1. Dissenya la corutina següent i desa-la al mòdul cintes (fitxer cintes.py):

    async cintes.gestiona_cinta(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) None

    Llegeix línia a línia de reader i respon OK per writer. Enregistra les excepcions mitjançant el mòdul logging. Fa un tancament net de writer quan s’acaben les dades de reader o s’ha produït una excepció.

  2. Passa-hi els tests del fitxer test_gestiona_cinta.py amb pytest.

  1. Dissenya un servidor basat en fluxos de dades (streams) d'asyncio que usi la corutina gestiona_cinta() per atendre cada una de les connexions. Desa’l al mòdul servidor_basic.

    • El servidor ha d’escoltar el port 7777 de l’ordinador local.

    • El servidor ha d’acabar de manera neta en rebre el senyal SIGTERM.

    Prova’l amb telnet o nc. Ha de respondre OK a cada línia enviada. Per exemple, havent engegat el servidor:

    $ nc -N 127.0.0.1 7777
    Hola
    OK
    Bon dia!
    OK
    Qualsevol cosa
    OK
    

Servidor amb l’estat de les cintes

El servidor ha d’emmagatzemar l’estat de cada cinta en un diccionari. Les claus del diccionari són els identificadors de les cintes. L’estat pot ser "ATURADA", "MOVIMENT" o "AVARIADA". El servidor ha de calcular l’estat de cada cinta a partir dels missatges rep de les cintes.

El protocol de missatges entre una cinta i el servidor és el següent:

  • El primer missatge que ha d’enviar una cinta al servidor és ID identificador_de_la_cinta en què identificador_de_la_cinta és un text sense espais en blanc. El servidor respon OK identificador_de_la_cinta.

  • La resta de missatges de la cinta poden ser:

    • VELOCITAT v en què v és un nombre més gran o igual que zero. El servidor ha de respondre OK ATURADA si v és igual a zero i OK MOVIMENT si v és més gran que zero.

    • AVARIA. El servidor respon OK ATURADA.

Recorda que cada missatge ha d’anar en una línia.

Cal que facis el següent:

  1. Dissenya la corutina següent i desa-la al mòdul cintes (fitxer cintes.py):

    async servidor_basic.gestiona_estat_cinta(estat, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) None

    Llegeix línia a línia de reader i respon per writer d’acord amb el protocol anterior. Emmagatzema l’estat de la cinta al diccionari estat. Enregistra les exepcions mitjançant el mòdul logging. Fa un tancament net de writer quan s’acaben les dades de reader o s’ha produït una excepció.

  2. Passa-hi els tests del fitxer test_gestiona_estat_cinta.py amb pytest.

  1. Dissenya un servidor basat en fluxos de dades (streams) d'asyncio que usi la corutina gestiona_estat_cinta() per atendre cada una de les connexions i que mantingui l’estat de cada cinta en un diccionari compartit per totes les connexions. Desa’l al mòdul servidor_estat.

    • El servidor ha d’escoltar el port 7777 de l’ordinador local.

    • El servidor ha d’acabar de manera neta en rebre el senyal SIGTERM.

    Prova’l amb telnet o nc. Recorda que has de seguir el protocol de la cinta. Per exemple, havent engegat el servidor:

    $ nc -N 127.0.0.1 7777
    ID cinta_1
    OK cinta_1
    VELOCITAT 100
    OK MOVIMENT
    VELOCITAT 0
    OK ATURADA
    AVARIA
    OK AVARIADA
    

Classe servidor

Ara volem reestructurar el codi anterior en una classe que implementi el Servidor amb l’estat de les cintes. Per això cal que facis el següent:

  1. Dissenya la classe següent i desa-la al mòdul servidor_classe:

    class servidor_classe.ServidorEstatCintes

    Implementa un servidor amb la mateixa funcionalitat que Servidor amb l’estat de les cintes.

    Atributs

    estat_cintes

    Diccionari amb l’estat de cada cinta connectada al servidor.

    Mètodes

    async cinta(reader: asyncio.StreamReader, writer: asyncio.StreamWriter)

    Equivalent a gestiona_estat_cinta(), llevat que el diccionari és un atribut de l’objecte en comptes de ser un paràmetre.

    async run(ip, port)

    Engega el servidor que escolta del port de l’adreça ip.

  2. Dissenya el programa que usi aquesta classe i desa’l al mòdul servidor_classe.

    Prova’l amb telnet o nc. S’ha de comportar com servidor_estat.

Prova de càrrega

Volem mesurar el nombre de peticions per segon que poden atendre els servidors anteriors. La prova de càrrega s’ha de comportar com wrk:

  • Parteix del nombre màxim de connexions i de la durada de la prova de càrrega en segons.

  • Ha de calcular:

    1. El nombre total de peticions fetes al servidor.

    2. El nombre d’errors produïts.

    3. El temps total d’execució.

    4. El rendiment del servidor en nombre de peticions ateses per segon.

Cal que facis el següent:

  1. Dissenya una prova de càrrega per als servidors anteriors que es comporti com wrk i desa-la al mòdul cintes_wrk. Per exemple:

    $ python3 cintes_wrk.py 10 5
    Iniciant prova de 5 segons amb 10 connexions concurrents...
    Protocol: TCP Stream sobre 127.0.0.1:7777
    
    ---------------------------------------------
    Peticions totals: 115721
    Errors totals:    0
    Temps real:       5.00 segons
    Rendiment (RPS):  23140.56 peticions/segon
    ---------------------------------------------