Cet article est partagé par la communauté Huawei Cloud « Le service Huawei Cloud SMS vous apprend à utiliser Perl pour implémenter le protocole Smgp », auteur : Zhang Jian.
Introduction et aperçu du protocole
China Telecom Short Message Gateway Protocol (SMGP) est un protocole de communication développé par China Netcom pour mettre en œuvre les services SMS. Son nom complet est Short Message Gateway Protocol. Il est utilisé entre la passerelle de messages courts (SMGW) et le fournisseur de services (SP). Communication entre la passerelle de messages courts (SMGW) et la passerelle de messages courts (SMGW).
Perl est un ancien langage de script installé par défaut sur de nombreux systèmes Linux. Par exemple, dans l'image de base de la version 22.04 d'Ubuntu, il n'y a même pas Python, mais Perl est toujours installé. La popularité de Perl est évidente. Le module IO::Async de Perl fournit un modèle de programmation IO asynchrone concis.
Le protocole SMGP fonctionne sur un modèle client/serveur. Le client (application SMS, telle qu'un téléphone mobile, une application, etc.) établit d'abord une longue connexion TCP avec la passerelle SMS (SMGW Short Message Gateway) et utilise les commandes CNGP pour interagir avec SMGW afin d'envoyer et de recevoir des messages SMS. Dans le protocole CNGP, la commande suivante peut être envoyée sans attendre de réponse de manière synchrone. Les implémenteurs peuvent implémenter deux modes de transmission de messages, synchrone et asynchrone, selon leurs propres besoins pour répondre aux exigences de performances dans différents scénarios.
Chronogramme
Connexion réussie, envoyer un SMS

Connexion réussie, SMS reçu de SMGW

Introduction aux trames de protocole
En-tête SMGP
L'en-tête contient les champs suivants, dont la taille et la longueur sont toutes de 4 octets
- Longueur du paquet : longueur de la PDU entière, y compris l'en-tête et le corps.
- ID de demande : utilisé pour identifier le type de PDU (par exemple, Connexion, Soumission, etc.).
- Sequence Id : numéro de séquence, utilisé pour faire correspondre les demandes et les réponses.
Utilisez Perl pour établir des connexions dans la pile de protocole SMGP
├── Makefile.PL ├── exemples │ └── smgp_client_login_example.pl └──lib └── Smgp ├── BoundAtomic.pm ├── Client.pm ├── Constant.pm └── Protocole.pm
exemples : stocke un exemple de code
- smgp_client_login_example.pl : stocke un exemple de connexion Smgp
- BoundAtomic.pm : classe d'outils incrémentielle utilisée pour générer SequenceId
- Client.pm : définition Smgp, responsable de la communication avec les services Smgp, comme l'établissement de connexions, l'envoi de messages texte, etc.
- Protocol.pm : stocke la PDU, le codec, etc.
Implémenter l'incrément séquence_id
séquence_id est une valeur comprise entre 1 et 0x7FFFFFFFF
paquet Smgp :: BoundAtomic ; utilisez strict ; utiliser les avertissements FATAL => 'all'; sous nouveau { mon ($class, %args) = @_; mon $ moi = { min => $args{min}, max => $args{max}, valeur => $args{min}, } ; bénissez-vous, $classe; retourner $self; } sous-incrément { mon ($moi) = @_; si ($self->{value} >= $self->{max}) { $self->{value} = $self->{min} ; } autre { $self->{valeur}++ ; } retourner $self->{value} ; } sous obtenir { mon ($moi) = @_; retourner $self->{value} ; } 1;
Définir la PDU SMGP et les fonctions d'encodage et de décodage en Perl
paquet Smgp :: Protocole ; utilisez strict ; utiliser les avertissements FATAL => 'all'; utilisez Smgp :: Constante ; sous new_login { mon ($class, %args) = @_; mon $ moi = { clientId => $args{clientId}, AuthenticatorClient => $args{authenticatorClient}, loginMode => $args{loginMode}, timeStamp => $args{timeStamp}, version => $args{version}, } ; revenir bénir $self, $class; } sous encode_login { mon ($moi) = @_; return pack("A8A16CNC", @{$self}{qw(clientId AuthenticatorClient loginMode timeStamp version)}); } sous decode_login_resp { mon ($class, $buffer) = @_; mon ($status, $authenticatorServer, $version) = unpack("N4A16C", $buffer); reviens bénisse { statut => $statut, AuthenticatorServer => $AuthenticatorServer, version => $version, }, $classe ; } sous new_header { mon ($class, %args) = @_; mon $ moi = { total_length => $args{total_length}, request_id => $args{request_id}, statut_commande => $args{status_commande}, séquence_id => $args{sequence_id}, } ; revenir bénir $self, $class; } sous encode_header { mon ($self, $total_length) = @_; return pack("N3", $total_length, @{$self}{qw(request_id séquence_id)}); } sous new_pdu { mon ($class, %args) = @_; mon $ moi = { en-tête => $args{en-tête}, corps => $args{corps}, } ; revenir bénir $self, $class; } sous encode_login_pdu { mon ($moi) = @_; mon $encoded_body = $self->{body}->encode_login(); return $self->{header}->encode_header(length($encoded_body) + 12) . $encoded_body; } sous decode_pdu { mon ($class, $buffer) = @_; mon ($request_id, $sequence_id) = unpack("N2", substr($buffer, 0, 8)); mon $body_buffer = substr($buffer, 8); mon $header = $class->new_header( longueur_totale => 0, request_id => $request_id, séquence_id => $séquence_id, ); mon $corps ; si ($request_id == Smgp::Constant::LOGIN_RESP_ID) { $body = $class->decode_login_resp($body_buffer); } autre { die "request_id non pris en charge : $request_id" ; } retourner $class->new_pdu( en-tête => $en-tête, corps => $corps, ); } 1;
constant.pm stocke le requestId associé
paquet Smgp :: Constante ; utilisez strict ; utiliser les avertissements FATAL => 'all'; utiliser la constante { ID_CONNEXION => 0x00000001, LOGIN_RESP_ID => 0x80000001, SUBMIT_ID => 0x00000002, SUBMIT_RESP_ID => 0x80000002, DELIVER_ID => 0x00000003, DELIVER_RESP_ID => 0x80000003, ACTIVE_TEST_ID => 0x00000004, ACTIVE_TEST_RESP_ID => 0x80000004, FORWARD_ID => 0x00000005, FORWARD_RESP_ID => 0x80000005, EXIT_ID => 0x00000006, EXIT_RESP_ID => 0x80000006, QUERY_ID => 0x00000007, QUERY_RESP_ID => 0x80000007, MT_ROUTE_UPDATE_ID => 0x00000008, MT_ROUTE_UPDATE_RESP_ID => 0x80000008, } ; 1;
Implémenter les méthodes client et de connexion
paquet Smgp :: Client ; utilisez strict ; utiliser les avertissements FATAL => 'all'; utilisez IO :: Socket :: INET ; utilisez Smgp :: Protocole ; utilisez Smgp :: Constante ; sous nouveau { mon ($class, %args) = @_; mon $ moi = { hôte => $args{hôte} // 'localhost', port => $args{port} // 9000, socket => undef, séquence_id => 1, } ; bénissez-vous, $classe; retourner $self; } sous-connecter { mon ($moi) = @_; $self->{socket} = IO::Socket::INET->nouveau( PeerHost => $self->{hôte}, PeerPort => $self->{port}, Proto => 'tcp', ) ou mourir "Impossible de se connecter à $self->{host}:$self->{port} $!"; } sous-connexion { mon ($soi, $corps) = @_; mon $header = Smgp::Protocol->new_header( request_id => Smgp::Constant::LOGIN_ID, séquence_id => 1, ); mon $pdu = Smgp::Protocol->new_pdu( en-tête => $en-tête, corps => $corps, ); $self->{socket}->send($pdu->encode_login_pdu()); $self->{socket}->recv(mon $response_length_bytes, 4); mon $total_length = unpack("N", $response_length_bytes); mon $remain_length = $total_length - 4 ; $self->{socket}->recv(mon $response_data, $remain_length); return Smgp::Protocol->decode_pdu($response_data)->{body}; } sous-déconnexion { mon ($moi) = @_; close($self->{socket}) if $self->{socket} ; } 1;
Exécutez l'exemple pour vérifier que la connexion est réussie
paquet smgp_client_login_example ; utilisez strict ; utiliser les avertissements FATAL => 'all'; utilisez Smgp::Client ; utilisez Smgp :: Protocole ; utilisez Smgp :: Constante ; principal sous { mon $client = Smgp::Client->new( hôte => 'localhost', port => 9000, ); $client->connect(); mon $login = Smgp::Protocol->new_login( ID client => '12345678', AuthenticatorClient => '1234567890123456', Mode de connexion => 1, timeStamp => heure(), version => 0, ); ma $response = $client->login($login); si ($réponse->{status} == 0) { print "Connexion réussie !\n" ; } autre { print "Échec de la connexion ! Statut : ", (défini $response->{status} ? $response->{status} : 'indéfini'), "\n"; } $client->déconnecter(); } main() sauf si l'appelant ; 1;
Projets open source associés
- netty-codec-sms stocke les codecs Netty pour divers protocoles SMS (tels que cmpp, sgip, smpp)
- sms-client-java stocke les clients Java de divers protocoles SMS
- sms-server-java stocke les serveurs Java pour divers protocoles SMS
- cmpp-python implémentation python du protocole cmpp
- implémentation python du protocole cngp-zig cmpp
- smgp-perl implémentation perl du protocole smgp
- smpp-rust rust implémentation du protocole smpp
Résumer
Cet article présente brièvement le protocole SMGP et tente d'utiliser Perl pour implémenter la pile de protocoles. Cependant, l'envoi de SMS commerciaux réels est souvent plus compliqué et se heurte à des problèmes tels que le contrôle de flux, l'interopérabilité des opérateurs et la sécurité de la couche de transport. Vous pouvez choisir Huawei Cloud Message. Le service & SMS (Message & SMS) est accessible via le protocole HTTP . Le service Huawei Cloud SMS est un service de communication fourni par Huawei Cloud aux utilisateurs d'entreprise en coopération avec de nombreux opérateurs et canaux de haute qualité à travers le monde. Les entreprises peuvent utiliser les services de code de vérification et de notification par SMS en appelant l'API ou en utilisant l'assistant d'envoi de groupe.
Cliquez pour suivre et découvrir les nouvelles technologies de Huawei Cloud dès que possible~