Vous apprendre à implémenter le protocole Smgp en utilisant Perl

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

image.png

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
Makefile.PL : utilisé pour générer le Makefile

exemples : stocke un exemple de code

  • smgp_client_login_example.pl : stocke un exemple de connexion Smgp
lib/Smgp : contient tous les fichiers du module Perl
  • 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;

image.png

Projets open source associés

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~

Un programmeur né dans les années 1990 a développé un logiciel de portage vidéo et en a réalisé plus de 7 millions en moins d'un an. La fin a été très éprouvante ! Google a confirmé les licenciements, impliquant la « malédiction des 35 ans » des codeurs chinois des équipes Flutter, Dart et . Python Arc Browser pour Windows 1.0 en 3 mois officiellement la part de marché de GA Windows 10 atteint 70 %, Windows 11 GitHub continue de décliner l'outil de développement natif d'IA GitHub Copilot Workspace JAVA. est la seule requête de type fort capable de gérer OLTP+OLAP. C'est le meilleur ORM. Nous nous rencontrons trop tard.
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/u/4526289/blog/11090249
conseillé
Classement