IPC client-serveur en multitraitement Python

L'article reflÚte l'expérience personnelle du développement d'applications CLI pour Linux.





Il explique comment le processus de super-utilisateur peut exécuter des appels systÚme privilégiés à la demande du programme de contrÎle via une API bien définie.





Le code source est écrit en Python pour une véritable application commerciale, mais extrait de tùches spécifiques pour la publication.





introduction

«La communication inter-processus (IPC) est l'Ă©change de donnĂ©es entre les threads d'un ou de diffĂ©rents processus. Il est mis en Ɠuvre via des mĂ©canismes fournis par le noyau du systĂšme d'exploitation ou par un processus qui utilise les mĂ©canismes du systĂšme d'exploitation et implĂ©mente de nouvelles capacitĂ©s IPC. - WikipĂ©dia





Les processus peuvent avoir diffĂ©rentes raisons d'Ă©changer des informations. À mon avis, ils sont tous une consĂ©quence de la politique de sĂ©curitĂ© du noyau Unix.





Comme vous le savez, le noyau Unix est un systÚme autonome qui fonctionne sans intervention humaine. En fait, un utilisateur est un objet du systÚme d'exploitation qui semble protéger le noyau des interférences non autorisées.





La sĂ©curitĂ© du noyau consiste Ă  diviser l' espace d'adressage du systĂšme d'exploitation en espace noyau et espace utilisateur . D'oĂč les deux modes de fonctionnement du systĂšme: le mode utilisateur et le mode noyau. De plus, un changement de mode est un basculement entre deux espaces.





En mode utilisateur, les zones de mémoire réservées par le noyau sont inaccessibles, tout comme les appels systÚme qui modifient l'état du systÚme.





Cependant, le superutilisateur a cet accĂšs.





Conditions préalables à la concurrence

Si votre programme n'utilise pas d'appels systÚme privilégiés, vous n'avez pas besoin d'un super-utilisateur, ce qui signifie que vous pouvez écrire un monolithe sans concurrence.





Sinon, vous devrez exécuter votre programme sous root.





, .





, , .





, , , , . , . , , , — .





IPC.






















, POSIX.









, POSIX.





(Message queue)





.









; , , Windows, , , IPC.









.









.









, POSIX.





(mmap)





, POSIX. . Windows , API, API, POSIX.





( )





MPI, Java RMI, CORBA .









.









, POSIX.









, POSIX.






API .





, , .





, , .





, , daemon. «d». : systemd.





, daemon , . : systemctl.





: ssh sshd.





, . , .





.





.
├── core
│   ├── api.py
│   └── __init__.py
├── main.py
      
      



core



— , . api



.





API

from multiprocessing.connection import Client
from multiprocessing.connection import Listener

#   (  )  
# 
daemon = ('localhost', 6000)
#   ( )  
#   
cli = ('localhost', 6001)

def send(request: dict) -> bool or dict:
    """
        .
     ,    
          .
    """
    with Client(daemon) as conn:
        conn.send(request)
    with Listener(cli) as listener:
        with listener.accept() as conn:
            try:
                return conn.recv()
            except EOFError:
                return False

def hello(name: str) -> send:
    """
         
    send   .
    """
    return send({
        "method": "hello",
        "name": name
    })

      
      



connection



multiprocessing



, API — socket.





Client



— , .





Listener



.





.





, Python, , . « » .





API

main.py



api



.





from core import api

response = api.hello("World!")
print(response)
      
      



. lick Framework LI , API.





API

, . .





def hello(request: dict) -> str:
    """
      .
    """
    return " ".join(["Hello", request["name"])

      
      



API

from core import api
from multiprocessing.connection import Listener
from multiprocessing.connection import Client

#   ( )   
daemon = ('localhost', 6000)
#     
cli = ('localhost', 6001)
while True:
    with Listener(daemon) as listener:
        with listener.accept() as conn:
            request = conn.recv()
            if request["method"] == "hello":
                response = api.hello(request)
            with Client(cli) as conn:
                conn.send(response)

      
      



, .





Ainsi, il Ă©coute toujours sur le port 6000 et analyse la requĂȘte lorsqu'un datagramme arrive. Ensuite, il appelle la mĂ©thode spĂ©cifiĂ©e dans la requĂȘte et renvoie le rĂ©sultat de l'exĂ©cution au client.





aditionellement

Je vous conseille d'Ă©quiper votre serveur du package systemd , qui permet aux programmes Python de se connecter Ă  journald .





Pour construire, vous pouvez utiliser pyinstaller - il emballera votre code dans un fichier binaire avec toutes les dépendances. N'oubliez pas la convention de dénomination des fichiers exécutables mentionnée précédemment.





Merci pour l'attention!








All Articles