Dieser Artikel wurde von der Huawei Cloud Community geteilt: „ Der Huawei Cloud SMS Service zeigt Ihnen, wie Sie Perl zum Implementieren des Smgp-Protokolls verwenden “, Autor: Zhang Jian.
Einführung und Protokollübersicht
Das China Telecom Short Message Gateway Protocol (SMGP) ist ein von China Netcom entwickeltes Kommunikationsprotokoll zur Implementierung von SMS-Diensten. Der vollständige Name lautet Short Message Gateway Protocol. Es wird zwischen dem Short Message Gateway (SMGW) und dem Service Provider (SP) verwendet. Kommunikation zwischen Short Message Gateway (SMGW) und Short Message Gateway (SMGW).
Perl ist eine alte Skriptsprache, die standardmäßig auf vielen Linux-Systemen installiert ist. Im Basis-Image der Version 22.04 von Ubuntu ist beispielsweise nicht einmal Python enthalten, aber Perl ist immer noch installiert. Das IO::Async-Modul von Perl bietet ein prägnantes asynchrones IO-Programmiermodell.
Das SMGP-Protokoll funktioniert auf einem Client/Server-Modell. Der Client (SMS-Anwendung wie Mobiltelefon, Anwendung usw.) stellt zunächst eine lange TCP-Verbindung mit dem SMS-Gateway (SMGW Short Message Gateway) her und interagiert mithilfe von CNGP-Befehlen mit SMGW, um SMS-Nachrichten zu senden und zu empfangen. Im CNGP-Protokoll kann der nächste Befehl synchron gesendet werden, ohne auf eine Antwort zu warten, je nach seinen eigenen Anforderungen, um die Leistungsanforderungen in verschiedenen Szenarien zu erfüllen.
Zeitdiagramm
Verbindung erfolgreich, SMS senden

Verbindung erfolgreich, SMS von SMGW empfangen

Einführung in Protokollrahmen
SMGP-Header
Der Header enthält die folgenden Felder, deren Größe und Länge jeweils 4 Bytes betragen
- Paketlänge : Die Länge der gesamten PDU, einschließlich Header und Body.
- Anforderungs-ID : Wird zur Identifizierung des PDU-Typs verwendet (z. B. Anmelden, Senden usw.).
- Sequenz-ID : Sequenznummer, die zum Abgleichen von Anfragen und Antworten verwendet wird.
Verwenden Sie Perl, um Verbindungen im SMGP-Protokollstapel herzustellen
├── Makefile.PL ├── Beispiele │ └── smgp_client_login_example.pl └── lib └── Smgp ├── BoundAtomic.pm ├── Kunde.pm ├── Constant.pm └── Protocol.pm
Beispiele: speichert Beispielcode
- smgp_client_login_example.pl: speichert Smgp-Anmeldebeispiel
- BoundAtomic.pm: Inkrementelle Toolklasse, die zum Generieren von SequenceId verwendet wird
- Client.pm: Smgp-Definition, verantwortlich für die Kommunikation mit Smgp-Diensten, z. B. Herstellen von Verbindungen, Senden von Textnachrichten usw.
- Protocol.pm: speichert PDU, Codec usw.
Implementieren Sie das Sequenz-ID-Inkrement
sequence_id ist ein Wert von 1 bis 0x7FFFFFFFF
Paket Smgp::BoundAtomic; streng verwenden; Warnungen verwenden FATAL => 'all'; Sub neu { my ($class, %args) = @_; mein $self = { min => $args{min}, max => $args{max}, value => $args{min}, }; segne $self, $class; return $self; } Unterinkrement { mein ($self) = @_; if ($self->{value} >= $self->{max}) { $self->{value} = $self->{min}; } anders { $self->{value}++; } return $self->{value}; } sub get { mein ($self) = @_; return $self->{value}; } 1;
Definieren Sie SMGP-PDU sowie Kodierungs- und Dekodierungsfunktionen in Perl
Paket Smgp::Protocol; streng verwenden; Warnungen verwenden FATAL => 'all'; benutze Smgp::Constant; sub new_login { my ($class, %args) = @_; mein $self = { clientId => $args{clientId}, AuthenticatorClient => $args{authenticatorClient}, loginMode => $args{loginMode}, timeStamp => $args{timeStamp}, version => $args{version}, }; return segne $self, $class; } sub encode_login { mein ($self) = @_; return pack("A8A16CNC", @{$self}{qw(clientId AuthenticatorClient loginMode timeStamp version)}); } sub decode_login_resp { my ($class, $buffer) = @_; my ($status, $authenticatorServer, $version) = unpack("N4A16C", $buffer); Rückkehr segnen { status => $status, AuthenticatorServer => $authenticatorServer, version => $version, }, $class; } sub new_header { my ($class, %args) = @_; mein $self = { total_length => $args{total_length}, request_id => $args{request_id}, command_status => $args{command_status}, sequence_id => $args{sequence_id}, }; return segne $self, $class; } sub encode_header { my ($self, $total_length) = @_; return pack("N3", $total_length, @{$self}{qw(request_id sequence_id)}); } sub new_pdu { my ($class, %args) = @_; mein $self = { header => $args{header}, body => $args{body}, }; return segne $self, $class; } sub encode_login_pdu { mein ($self) = @_; my $encoded_body = $self->{body}->encode_login(); return $self->{header}->encode_header(length($encoded_body) + 12) . $encoded_body; } sub decode_pdu { my ($class, $buffer) = @_; my ($request_id, $sequence_id) = unpack("N2", substr($buffer, 0, 8)); mein $body_buffer = substr($buffer, 8); mein $header = $class->new_header( total_length => 0, request_id => $request_id, sequence_id => $sequence_id, ); mein $körper; if ($request_id == Smgp::Constant::LOGIN_RESP_ID) { $body = $class->decode_login_resp($body_buffer); } anders { die „Nicht unterstützte request_id: $request_id“; } return $class->new_pdu( header => $header, body => $body, ); } 1;
konstant.pm speichert die zugehörige Anforderungs-ID
Paket Smgp::Constant; streng verwenden; Warnungen verwenden FATAL => 'all'; verwende die Konstante { LOGIN_ID => 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;
Implementieren Sie Client- und Anmeldemethoden
Paket Smgp::Client; streng verwenden; Warnungen verwenden FATAL => 'all'; verwenden IO::Socket::INET; benutze Smgp::Protocol; benutze Smgp::Constant; Sub neu { my ($class, %args) = @_; mein $self = { host => $args{host} // 'localhost', port => $args{port} // 9000, socket => undef, sequence_id => 1, }; segne $self, $class; return $self; } Unterverbindung { mein ($self) = @_; $self->{socket} = IO::Socket::INET->new( PeerHost => $self->{host}, PeerPort => $self->{port}, Proto => 'tcp', ) oder sterben „Es kann keine Verbindung zu $self->{host}:$self->{port} $ hergestellt werden!“; } Sub-Login { my ($self, $body) = @_; mein $header = Smgp::Protocol->new_header( request_id => Smgp::Constant::LOGIN_ID, sequence_id => 1, ); my $pdu = Smgp::Protocol->new_pdu( header => $header, body => $body, ); $self->{socket}->send($pdu->encode_login_pdu()); $self->{socket}->recv(my $response_length_bytes, 4); my $total_length = unpack("N", $response_length_bytes); meine $remain_length = $total_length - 4; $self->{socket}->recv(my $response_data, $remain_length); return Smgp::Protocol->decode_pdu($response_data)->{body}; } Untertrennung { mein ($self) = @_; close($self->{socket}) if $self->{socket}; } 1;
Führen Sie ein Beispiel aus, um zu überprüfen, ob die Verbindung erfolgreich ist
Paket smgp_client_login_example; streng verwenden; Warnungen verwenden FATAL => 'all'; benutze Smgp::Client; benutze Smgp::Protocol; benutze Smgp::Constant; Unterhaupt { mein $client = Smgp::Client->new( host => 'localhost', Port => 9000, ); $client->connect(); mein $login = Smgp::Protocol->new_login( clientId => '12345678', AuthenticatorClient => '1234567890123456', loginMode => 1, timeStamp => time(), Version => 0, ); my $response = $client->login($login); if ($response->{status} == 0) { print „Anmeldung erfolgreich!\n“; } anders { print „Anmeldung fehlgeschlagen! Status:“, (definiert $response->{status} ? $response->{status} : ‚undefiniert‘), „\n“; } $client->disconnect(); } main(), es sei denn, der Aufrufer; 1;
Verwandte Open-Source-Projekte
- netty-codec-sms speichert Netty-Codecs für verschiedene SMS-Protokolle (wie cmpp, sgip, smpp)
- sms-client-java speichert Java-Clients verschiedener SMS-Protokolle
- sms-server-java speichert Java-Server für verschiedene SMS-Protokolle
- cmpp-python Python-Implementierung des cmpp-Protokolls
- Python-Implementierung des CNGP-Zig- CMPP-Protokolls
- smgp-perl Perl-Implementierung des SMGP-Protokolls
- smpp-rust Rust-Implementierung des SMPP-Protokolls
Zusammenfassen
In diesem Artikel wird das SMGP-Protokoll kurz vorgestellt und versucht, den Protokollstapel mit Perl zu implementieren. Der tatsächliche kommerzielle SMS -Versand ist jedoch häufig komplizierter und weist Probleme wie Flusskontrolle, Betreiberinteroperabilität und Transportschichtsicherheit auf Der Zugriff auf den SMS-Dienst (Message & SMS) erfolgt über das HTTP-Protokoll . Der Huawei Cloud SMS-Dienst ist ein Kommunikationsdienst, der Unternehmensbenutzern von Huawei Cloud in Zusammenarbeit mit vielen hochwertigen Betreibern und Kanälen auf der ganzen Welt bereitgestellt wird. Unternehmen können Verifizierungscode- und Benachrichtigungs-SMS-Dienste nutzen, indem sie die API aufrufen oder den Gruppenversand-Assistenten verwenden.