Ensine como implementar o protocolo Smgp usando Perl

Este artigo é compartilhado pela Huawei Cloud Community "O Huawei Cloud SMS Service ensina você a usar Perl para implementar o protocolo Smgp ", autor: Zhang Jian.

Introdução e visão geral do protocolo

O China Telecom Short Message Gateway Protocol (SMGP) é um protocolo de comunicação desenvolvido pela China Netcom para implementar serviços SMS. Seu nome completo é Short Message Gateway Protocol. É usado entre o Short Message Gateway (SMGW) e o Provedor de Serviços (SP). Comunicação entre Short Message Gateway (SMGW) e Short Message Gateway (SMGW).

Perl é uma linguagem de script antiga instalada por padrão em muitos sistemas Linux. Por exemplo, na imagem base da versão 22.04 do Ubuntu, não há nem Python, mas o Perl ainda está instalado. O módulo IO::Async do Perl fornece um modelo de programação IO assíncrono conciso.

O protocolo SMGP funciona em um modelo cliente/servidor. O cliente (aplicativo SMS, como telefone celular, aplicativo, etc.) primeiro estabelece uma conexão TCP longa com o gateway SMS (gateway de mensagens curtas SMGW) e usa comandos CNGP para interagir com o SMGW para enviar e receber mensagens SMS. No protocolo CNGP, o próximo comando pode ser enviado sem esperar por uma resposta de forma síncrona. Os implementadores podem implementar dois modos de transmissão de mensagens, síncronos e assíncronos, de acordo com suas próprias necessidades para atender aos requisitos de desempenho em diferentes cenários.

Diagrama de tempo

Conexão bem-sucedida, envie mensagem de texto

 
 
 

Conexão bem-sucedida, SMS recebido do SMGW

 
 
 

Introdução aos quadros de protocolo

imagem.png

Cabeçalho SMGP

O cabeçalho contém os seguintes campos, cujo tamanho e comprimento são todos de 4 bytes

  • Comprimento do pacote : O comprimento de toda a PDU, incluindo cabeçalho e corpo.
  • Request ID : Usado para identificar o tipo de PDU (por exemplo, Login, Submit, etc.).
  • Id de sequência : número de sequência, usado para combinar solicitações e respostas.

Use perl para estabelecer conexões na pilha de protocolos SMGP

├── Makefile.PL
├── exemplos
│ └── smgp_client_login_example.pl
└──lib
    └── Smgp
        ├── BoundAtomic.pm
        ├── Cliente.pm
        ├── Constante.pm
        └── Protocolo.pm
Makefile.PL : usado para gerar Makefile

exemplos: armazena código de amostra

  • smgp_client_login_example.pl: armazena exemplo de login Smgp
lib/Smgp: Contém todos os arquivos do módulo Perl
  • BoundAtomic.pm: classe de ferramenta incremental usada para gerar SequenceId
  • Client.pm: definição do Smgp, responsável pela comunicação com os serviços do Smgp, como estabelecer conexões, enviar mensagens de texto, etc.
  • Protocol.pm: armazena PDU, codec, etc.

Implementar incremento de sequence_id

sequencia_id é um valor de 1 a 0x7FFFFFFFF

pacote Smgp::BoundAtomic;

use estrito;
use avisos FATAL => 'todos';

sub novo {
    minha ($classe,%args) = @_;
    meu $self = {
        min => $args{min},
        máximo => $args{máximo},
        valor => $args{min},
    };
    abençoe $self, $class;
    retornar $self;
}

subincremento {
    meu ($self) = @_;
    if ($self->{valor} >= $self->{max}) {
        $self->{valor} = $self->{min};
    } outro {
        $self->{valor}++;
    }
    retornar $self->{valor};
}

sub obter {
    meu ($self) = @_;
    retornar $self->{valor};
}

1;

Definir SMGP PDU e funções de codificação e decodificação em Perl

pacote Smgp::Protocolo;

use estrito;
use avisos FATAL => 'todos';

use Smgp::Constante;

sub new_login {
    minha ($classe,%args) = @_;
    meu $self = {
        clienteId => $args{clientId},
        authenticatorClient => $args{authenticatorClient},
        loginMode => $args{loginMode},
        timeStamp => $args{timeStamp},
        versão => $args{versão},
    };
    return abençoe $self, $class;
}

subencode_login {
    meu ($self) = @_;
    return pack("A8A16CNC", @{$self}{qw(clientId authenticatorClient loginMode timeStamp version)});
}

subdecode_login_resp {
    minha ($classe, $buffer) = @_;
    meu ($status, $authenticatorServer, $versão) = unpack("N4A16C", $buffer);
    retorne abençoado {
        status => $ status,
        authenticatorServer => $authenticatorServer,
        versão => $versão,
    }, $classe;
}

sub novo_cabeçalho {
    minha ($classe,%args) = @_;
    meu $self = {
        comprimento_total => $args{comprimento_total},
        request_id => $args{request_id},
        status_de_comando => $args{status_de_comando},
        sequência_id => $args{sequence_id},
    };
    return abençoe $self, $class;
}

subencode_header {
    meu ($self, $total_length) = @_;
    return pack("N3", $total_length, @{$self}{qw(request_id sequencia_id)});
}

sub new_pdu {
    minha ($classe,%args) = @_;
    meu $self = {
        cabeçalho => $args{cabeçalho},
        corpo => $args{corpo},
    };
    return abençoe $self, $class;
}

subencode_login_pdu {
    meu ($self) = @_;
    meu $encoded_body = $self->{body}->encode_login();
    retorne $self->{header}->encode_header(length($encoded_body) + 12) . $encoded_body;
}

sub decode_pdu {
    minha ($classe, $buffer) = @_;
    meu ($request_id, $sequence_id) = unpack("N2", substr($buffer, 0, 8));
    meu $body_buffer = substr($buffer, 8);

    meu $header = $class->new_header(
        comprimento_total => 0,
        request_id => $ request_id,
        sequência_id => $sequence_id,
    );

    meu $corpo;
    if ($request_id == Smgp::Constant::LOGIN_RESP_ID) {
        $body = $class->decode_login_resp($body_buffer);
    } outro {
        morrer "solicitação_id não suportada: $request_id";
    }

    retorne $class->new_pdu(
        cabeçalho => $ cabeçalho,
        corpo => $corpo,
    );
}

1;

constante.pm armazena requestId relacionado

pacote Smgp::Constante;

use estrito;
use avisos FATAL => 'todos';

usar constante {
    LOGIN_ID => 0x00000001,
    LOGIN_RESP_ID => 0x80000001,
    ENVIAR_ID => 0x00000002,
    ENVIAR_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;

Implementar métodos de cliente e login

pacote Smgp::Cliente;
use estrito;
use avisos FATAL => 'todos';
use IO::Socket::INET;

use Smgp::Protocolo;
use Smgp::Constante;

sub novo {
    minha ($classe,%args) = @_;
    meu $self = {
        host => $args{host} // 'localhost',
        porta => $args{porta} // 9000,
        soquete => undef,
        sequência_id => 1,
    };
    abençoe $self, $class;
    retornar $self;
}

subconectar {
    meu ($self) = @_;
    $self->{socket} = IO::Socket::INET->new(
        PeerHost => $self->{host},
        PeerPort => $self->{porta},
        Proto => 'tcp',
    ) ou morrer "Não é possível conectar-se a $self->{host}:$self->{port} $!";
}

sublogin {
    meu ($self, $corpo) = @_;
    meu $header = Smgp::Protocol->new_header(
        request_id => Smgp::Constant::LOGIN_ID,
        sequência_id => 1,
    );

    meu $pdu = Smgp::Protocol->new_pdu(
        cabeçalho => $ cabeçalho,
        corpo => $corpo,
    );

    $self->{socket}->send($pdu->encode_login_pdu());

    $self->{socket}->recv(meu $response_length_bytes, 4);

    meu $total_length = unpack("N", $response_length_bytes);
    meu $remain_length = $total_length - 4;
    $self->{socket}->recv(meu $response_data, $remain_length);

    return Smgp::Protocol->decode_pdu($response_data)->{body};
}

subdesconexão {
    meu ($self) = @_;
    fechar($self->{socket}) se $self->{socket};
}

1;

Execute o exemplo para verificar se a conexão foi bem-sucedida

pacote smgp_client_login_example;

use estrito;
use avisos FATAL => 'todos';

use Smgp::Cliente;
use Smgp::Protocolo;
use Smgp::Constante;

sub principal {
    meu $cliente = Smgp::Cliente->new(
        host => 'localhost',
        porta => 9000,
    );

    $cliente->conectar();

    meu $login = Smgp::Protocol->new_login(
        clienteId => '12345678',
        authenticatorClient => '1234567890123456',
        loginMode => 1,
        timeStamp => hora(),
        versão => 0,
    );

    minha $resposta = $client->login($login);

    if ($resposta->{status} == 0) {
        print "Login realizado com sucesso!\n";
    }
    outro {
        print "Falha no login! Status: ", (definido $response->{status} ? $response->{status} : 'indefinido'), "\n";
    }

    $cliente->desconectar();
}

main() a menos que chamador;

1;

imagem.png

Projetos de código aberto relacionados

Resumir

Este artigo apresenta brevemente o protocolo SMGP e tenta usar perl para implementar a pilha de protocolos. No entanto, o envio comercial real de SMS costuma ser mais complicado e enfrenta problemas como controle de fluxo, interoperabilidade do operador e segurança da camada de transporte . O serviço & SMS (Mensagem e SMS) é acessado através do protocolo HTTP . O serviço SMS da Huawei Cloud é um serviço de comunicação fornecido pela Huawei Cloud para usuários corporativos em cooperação com muitas operadoras e canais de alta qualidade em todo o mundo. As empresas podem usar código de verificação e serviços de notificação por SMS chamando a API ou usando o assistente de envio de grupo.

Clique para seguir e conhecer as novas tecnologias da Huawei Cloud o mais rápido possível~

Um programador nascido na década de 1990 desenvolveu um software de portabilidade de vídeo e faturou mais de 7 milhões em menos de um ano. O final foi muito punitivo! Google confirmou demissões, envolvendo a "maldição de 35 anos" dos programadores chineses nas equipes Flutter, Dart e . Python Arc Browser para Windows 1.0 em 3 meses oficialmente GA A participação de mercado do Windows 10 atinge 70%, Windows 11 GitHub continua a diminuir a ferramenta de desenvolvimento nativa de IA GitHub Copilot Workspace JAVA. é a única consulta de tipo forte que pode lidar com OLTP + OLAP. Este é o melhor ORM. Nos encontramos tarde demais.
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/4526289/blog/11090249
Recomendado
Clasificación