Perl을 사용하여 Smgp 프로토콜을 구현하는 방법을 가르칩니다.

이 기사는 Huawei Cloud 커뮤니티 " Huawei Cloud SMS 서비스에서 Perl을 사용하여 Smgp 프로토콜을 구현하는 방법을 안내합니다 "에서 공유되었습니다. 저자: Zhang Jian.

소개 및 프로토콜 개요

SMGP(China Telecom Short Message Gateway Protocol)는 SMS 서비스를 구현하기 위해 China Netcom에서 개발한 통신 프로토콜입니다. 정식 이름은 SMGW(단문 메시지 게이트웨이)와 서비스 공급자(SP) 간에 사용됩니다. SMGW(단문 메시지 게이트웨이)와 SMGW(단문 메시지 게이트웨이) 간의 통신입니다.

Perl은 많은 Linux 시스템에 기본적으로 설치되는 오래된 스크립트 언어입니다. 예를 들어 Ubuntu 버전 22.04의 기본 이미지에는 Python조차 없지만 Perl의 인기는 여전히 분명합니다. Perl의 IO::Async 모듈은 간결한 비동기 IO 프로그래밍 모델을 제공합니다.

SMGP 프로토콜은 클라이언트/서버 모델에서 작동합니다. 클라이언트(휴대폰, 애플리케이션 등의 SMS 애플리케이션)는 먼저 SMS 게이트웨이(SMGW 짧은 메시지 게이트웨이)와 긴 TCP 연결을 설정하고 CNGP 명령을 사용하여 SMGW와 상호 작용하여 SMS 메시지를 보내고 받습니다. CNGP 프로토콜에서는 동기적으로 응답을 기다리지 않고 다음 명령을 보낼 수 있습니다. 구현자는 다양한 시나리오의 성능 요구 사항을 충족하기 위해 자체 요구 사항에 따라 동기식과 비동기식의 두 가지 메시지 전송 모드를 구현할 수 있습니다.

타이밍 다이어그램

연결에 성공했습니다. 문자 메시지를 보내세요.

 
 
 

연결 성공, SMGW로부터 SMS 수신됨

 
 
 

프로토콜 프레임 소개

이미지.png

SMGP 헤더

헤더에는 다음 필드가 포함되며 크기와 길이는 모두 4바이트입니다.

  • 패킷 길이 : 헤더와 본문을 포함한 전체 PDU의 길이입니다.
  • 요청 ID : PDU 유형(예: 로그인, 제출 등)을 식별하는 데 사용됩니다.
  • Sequence Id : 요청과 응답을 일치시키는 데 사용되는 시퀀스 번호입니다.

Perl을 사용하여 SMGP 프로토콜 스택에서 연결 설정

├── Makefile.PL
├── 예시
│ └── smgp_client_login_example.pl
└── lib
    └── Smgp
        ├── BoundAtomic.pm
        ├── Client.pm
        ├── 상수.pm
        └── 프로토콜.pm
Makefile.PL : Makefile을 생성하는 데 사용됩니다.

예: 샘플 코드 저장

  • smgp_client_login_example.pl: Smgp 로그인 예제를 저장합니다.
lib/Smgp: 모든 Perl 모듈 파일을 포함합니다.
  • BoundAtomic.pm: SequenceId를 생성하는 데 사용되는 증분 도구 클래스
  • Client.pm: 연결 설정, 문자 메시지 보내기 등과 같은 Smgp 서비스와의 통신을 담당하는 Smgp 정의입니다.
  • Protocol.pm: PDU, 코덱 등을 저장합니다.

시퀀스 ID 증분 구현

Sequence_id는 1에서 0x7FFFFFFFF 사이의 값입니다.

패키지 Smgp::BoundAtomic;

엄격하게 사용하십시오.
경고 사용 FATAL => 'all';

하위 새로운 {
    내 ($class, %args) = @_;
    내 $self = {
        최소 => $args{min},
        최대 => $args{최대},
        값 => $args{min},
    };
    $self, $class를 축복하세요.
    $self를 반환합니다.
}

하위 증분 {
    내 ($self) = @_;
    if ($self->{값} >= $self->{최대}) {
        $self->{값} = $self->{min};
    } 또 다른 {
        $self->{값}++;
    }
    $self->{값}을 반환합니다.
}

서브는 {를 얻습니다
    내 ($self) = @_;
    $self->{값}을 반환합니다.
}

1;

Perl에서 SMGP PDU와 인코딩 및 디코딩 기능 정의

패키지 Smgp::프로토콜;

엄격하게 사용하십시오.
경고 사용 FATAL => 'all';

Smgp::Constant를 사용하세요.

하위 new_login {
    내 ($class, %args) = @_;
    내 $self = {
        clientId => $args{clientId},
        인증자 클라이언트 => $args{authenticatorClient},
        로그인 모드 => $args{loginMode},
        타임스탬프 => $args{timeStamp},
        버전 => $args{버전},
    };
    $self, $class를 축복해 주세요;
}

하위 encode_login {
    내 ($self) = @_;
    return pack("A8A16CNC", @{$self}{qw(clientIdAuthenticatorClient loginMode timeStamp version)});
}

하위 decode_login_resp {
    내 ($class, $buffer) = @_;
    내 ($status, $authenticatorServer, $version) = unpack("N4A16C", $buffer);
    축복을 돌려주세요 {
        상태 => $상태,
        인증 서버 => $ 인증 서버,
        버전 => $버전,
    }, $클래스;
}

하위 new_header {
    내 ($class, %args) = @_;
    내 $self = {
        총_길이 => $args{총_길이},
        request_id => $args{request_id},
        command_status => $args{command_status},
        시퀀스_ID => $args{시퀀스_ID},
    };
    $self, $class를 축복해 주세요;
}

하위 encode_header {
    내 ($self, $total_length) = @_;
    return pack("N3", $total_length, @{$self}{qw(request_id 시퀀스_id)});
}

하위 new_pdu {
    내 ($class, %args) = @_;
    내 $self = {
        헤더 => $args{헤더},
        본문 => $args{본문},
    };
    $self, $class를 축복해 주세요;
}

하위 encode_login_pdu {
    내 ($self) = @_;
    내 $encoded_body = $self->{body}->encode_login();
    $self->{header}->encode_header(length($encoded_body) + 12) 를 반환합니다. $encoded_body;
}

하위 디코드_pdu {
    내 ($class, $buffer) = @_;
    my ($request_id, $sequence_id) = unpack("N2", substr($buffer, 0, 8));
    내 $body_buffer = substr($buffer, 8);

    내 $header = $class->new_header(
        총 길이 => 0,
        request_id => $request_id,
        시퀀스_ID => $시퀀스_ID,
    );

    내 $body;
    if ($request_id == Smgp::Constant::LOGIN_RESP_ID) {
        $body = $class->decode_login_resp($body_buffer);
    } 또 다른 {
        die "지원되지 않는 request_id: $request_id";
    }

    $class->new_pdu(를 반환합니다.
        헤더 => $헤더,
        몸 => $몸,
    );
}

1;

Constant.pm은 관련 requestId를 저장합니다.

패키지 Smgp::상수;

엄격하게 사용하십시오.
경고 사용 FATAL => 'all';

상수 사용 {
    로그인_ID => 0x00000001,
    LOGIN_RESP_ID => 0x80000001,
    SUBMIT_ID => 0x00000002,
    SUBMIT_RESP_ID => 0x80000002,
    배달_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;

클라이언트 및 로그인 방법 구현

패키지 Smgp::클라이언트;
엄격하게 사용하십시오.
경고 사용 FATAL => 'all';
IO::소켓::INET을 사용합니다.

Smgp::프로토콜을 사용합니다.
Smgp::Constant를 사용하세요.

하위 새로운 {
    내 ($class, %args) = @_;
    내 $self = {
        호스트 => $args{host} // 'localhost',
        포트 => $args{port} // 9000,
        소켓 => undef,
        시퀀스_ID => 1,
    };
    $self, $class를 축복하세요.
    $self를 반환합니다.
}

하위 연결 {
    내 ($self) = @_;
    $self->{소켓} = IO::소켓::INET->새(
        PeerHost => $self->{호스트},
        PeerPort => $self->{포트},
        프로토 => 'TCP',
    ) 또는 사망 "$self->{host}:$self->{port} $에 연결할 수 없습니다!";
}

하위 로그인 {
    내 ($self, $body) = @_;
    내 $header = Smgp::Protocol->new_header(
        request_id => Smgp::상수::LOGIN_ID,
        시퀀스_ID => 1,
    );

    내 $pdu = Smgp::프로토콜->new_pdu(
        헤더 => $헤더,
        몸 => $몸,
    );

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

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

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

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

하위 연결 해제 {
    내 ($self) = @_;
    close($self->{socket}) if $self->{socket};
}

1;

예제를 실행하여 연결이 성공했는지 확인하세요.

패키지 smgp_client_login_example;

엄격하게 사용하십시오.
경고 사용 FATAL => 'all';

Smgp::클라이언트를 사용합니다.
Smgp::프로토콜을 사용합니다.
Smgp::Constant를 사용하세요.

서브 메인 {
    내 $client = Smgp::Client->new(
        호스트 => '로컬 호스트',
        포트 => 9000,
    );

    $클라이언트->연결();

    내 $login = Smgp::프로토콜->new_login(
        클라이언트 ID => '12345678',
        인증자 클라이언트 => '1234567890123456',
        로그인 모드 => 1,
        타임스탬프 => 시간(),
        버전 => 0,
    );

    내 $response = $client->login($login);

    if ($response->{status} == 0) {
        "로그인 성공!\n"을 인쇄합니다.
    }
    또 다른 {
        print "로그인 실패! 상태: ", ($response->{status} ? $response->{status} 정의됨: 'undefine'), "\n";
    }

    $클라이언트->연결 끊기();
}

호출자가 아닌 경우 main();

1;

이미지.png

관련 오픈소스 프로젝트

  • netty-codec-sms는  다양한 SMS 프로토콜(예: cmpp, sgip, smpp)에 대한 netty 코덱을 저장합니다.
  • sms-client-java는  다양한 SMS 프로토콜의 Java 클라이언트를 저장합니다.
  • sms-server-java는  다양한 SMS 프로토콜용 Java 서버를 저장합니다.
  • cmpp-python  cmpp 프로토콜의 Python 구현
  • cngp-zig  cmpp 프로토콜 의 Python 구현
  • smgp-perl  smgp 프로토콜의 perl 구현
  • smpp-rust  smpp 프로토콜의 녹 구현

요약하다

이 기사에서는 SMGP 프로토콜 을 간략하게 소개하고 Perl을 사용하여 프로토콜 스택을 구현하려고 시도합니다. 그러나 실제 상용 SMS 전송은 종종 더 복잡하고 흐름 제어, 운영자 상호 운용성 및 전송 계층 보안과 같은 문제에 직면합니다. & SMS(메시지 및 SMS) 서비스는 HTTP 프로토콜을 통해 액세스됩니다 . Huawei Cloud SMS 서비스 는 Huawei Cloud가 전 세계 수많은 고품질 통신업체 및 채널과 협력하여 기업 사용자에게 제공하는 통신 서비스입니다. 기업에서는 API를 호출하거나 그룹발송 도우미를 이용하여 인증번호 및 알림 SMS 서비스를 이용할 수 있습니다.

화웨이 클라우드의 신기술에 대해 빨리 알아보고 팔로우하려면 클릭하세요~

1990년대에 태어난 프로그래머가 비디오 포팅 소프트웨어를 개발하여 1년도 안 되어 700만 개 이상의 수익을 올렸습니다. 결말은 매우 처참했습니다! Google은 Flutter, Dart 및 Python 팀의 중국 코더의 "35세 저주"와 관련된 정리해고를 확인했습니다 . | Daily Windows 1.0용 Arc Browser가 3개월 만에 공식적으로 GA Windows 10 시장 점유율이 70%에 도달했으며 Windows 11 GitHub는 AI 기본 개발 도구 GitHub Copilot Workspace JAVA를 계속해서 출시했습니다 . OLTP+OLAP을 처리할 수 있는 유일한 강력한 유형의 쿼리입니다. 우리는 너무 늦게 만났습니다 .
{{o.이름}}
{{이름}}

추천

출처my.oschina.net/u/4526289/blog/11090249