Erfahren Sie, wie Sie das Smgp-Protokoll mit Perl implementieren

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

Bild.png

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
Makefile.PL : Wird zum Generieren von Makefile verwendet

Beispiele: speichert Beispielcode

  • smgp_client_login_example.pl: speichert Smgp-Anmeldebeispiel
lib/Smgp: Enthält alle Perl-Moduldateien
  • 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;

Bild.png

Verwandte Open-Source-Projekte

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.

Klicken Sie hier, um zu folgen und so schnell wie möglich mehr über die neuen Technologien von Huawei Cloud zu erfahren~

Ein in den 1990er Jahren geborener Programmierer hat eine Videoportierungssoftware entwickelt und in weniger als einem Jahr über 7 Millionen verdient. Das Ende war sehr bestrafend! Google bestätigte Entlassungen, die den „35-jährigen Fluch“ chinesischer Programmierer in den Flutter-, Dart- und Teams- Python mit sich brachten stark und wird von GPT-4.5 vermutet; Tongyi Qianwen Open Source 8 Modelle Arc Browser für Windows 1.0 in 3 Monaten offiziell GA Windows 10 Marktanteil erreicht 70 %, Windows 11 GitHub veröffentlicht weiterhin KI-natives Entwicklungstool GitHub Copilot Workspace JAVA ist die einzige starke Abfrage, die OLTP+OLAP verarbeiten kann. Dies ist das beste ORM. Wir treffen uns zu spät.
{{o.name}}
{{m.name}}

Ich denke du magst

Origin my.oschina.net/u/4526289/blog/11090249
Empfohlen
Rangfolge