이 기사는 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 수신됨
프로토콜 프레임 소개
SMGP 헤더
헤더에는 다음 필드가 포함되며 크기와 길이는 모두 4바이트입니다.
- 패킷 길이 : 헤더와 본문을 포함한 전체 PDU의 길이입니다.
- 요청 ID : PDU 유형(예: 로그인, 제출 등)을 식별하는 데 사용됩니다.
- Sequence Id : 요청과 응답을 일치시키는 데 사용되는 시퀀스 번호입니다.
Perl을 사용하여 SMGP 프로토콜 스택에서 연결 설정
├── Makefile.PL ├── 예시 │ └── smgp_client_login_example.pl └── lib └── Smgp ├── BoundAtomic.pm ├── Client.pm ├── 상수.pm └── 프로토콜.pm
예: 샘플 코드 저장
- smgp_client_login_example.pl: Smgp 로그인 예제를 저장합니다.
- 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;
관련 오픈소스 프로젝트
- 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 서비스를 이용할 수 있습니다.