您的位置:

CMPP2.0协议详述

一、CMPP2.0协议概述

中国移动短信网关是全球最大的移动短信平台之一,其协议主要包括SMPP、CMPP、SGIP等。CMPP(China Mobile Peer to Peer)是中国移动基于TCP/IP协议栈实现的短信网关协议,CMPP2.0是其第二个版本,是目前最为普遍采用的版本。

CMPP2.0采用二进制格式进行消息传输,具有高效、稳定的特点。通过CMPP2.0协议,短信发送方可以将短信发送到中国移动短信网关,网关再将短信转发到接收方的手机上。需要注意的是,CMPP2.0协议中的短信发送和接受都是异步的。

二、CMPP2.0协议结构

CMPP2.0协议报文结构主要包括消息头、消息体和消息尾三部分。

1. 消息头

消息头包括以下内容:

struct cmpp3_header {
  unsigned int total_length;  // 消息总长度
  unsigned int command_id;    // 命令标识
  unsigned int sequence_id;   // 消息序列号
};

其中,total_length表示整个消息的长度,包括消息头、消息体和消息尾;command_id表示消息类型;sequence_id表示消息序列号,用于标识服务器的响应。

2. 消息体

消息体中包含具体的业务数据。不同的消息类型有着不同的消息体格式。例如,CMPP_CONNECT消息中包含SP_Id、Secret等字段;CMPP_SUBMIT消息中包含短信内容、短信号码等字段。

3. 消息尾

消息尾主要是用来填充报文,保证整个报文的长度为8的倍数,方便数据传输和处理。

三、CMPP2.0协议消息类型

CMPP2.0协议一共支持9种不同类型的消息,分别是:

  • CMPP_CONNECT请求/响应消息:用于建立和中断连接;
  • CMPP_TERMINATE请求/响应消息:用于正常关闭与服务器的连接;
  • CMPP_SUBMIT请求/响应消息:用于提交短信;
  • CMPP_DELIVER请求/响应消息:用于接收短信;
  • CMPP_QUERY请求/响应消息:用于查询状态报告;
  • CMPP_CANCEL请求/响应消息:用于取消提交的短信;
  • CMPP_ACTIVE_TEST请求/响应消息:用于测试连接状态;
  • CMPP_FWD请求/响应消息:用于将短信转发到其他号码;
  • CMPP_MT_ROUTE请求/响应消息:用于短信路由管理。

四、CMPP2.0协议示例代码

1. 建立连接

下面是建立连接的示例代码。目前,中国移动短信网关提供IP地址为60.12.13.50的网关,可以在测试时直接使用。

# 定义IP和端口号
HOST = '60.12.13.50'
PORT = 7890

# 连接服务器
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))

# 发送CMPP_CONNECT请求
connect_msg = pack('>III6s16s3sI', 39, 0x00000001, 1, '', 'user', 'pass', int(time.time()))
sock.send(connect_msg)
resp_msg = sock.recv(1024)

# 解析CMPP_CONNECT响应
total_length, command_id, status = unpack('>III', resp_msg[:12])

if command_id == 0x80000001 and status == 0:
    print('Connect OK')
else:
    print('Connect failed')
    sock.close()

2. 提交短信

下面是提交短信的示例代码。在代码中,SP_id、src_id和msg_content等参数需要替换成实际的值。

# 获取消息流水号
sequence_id = random.randint(1, 65535)

# 构造CMPP_SUBMIT消息
msg_content = '测试短信'
msg_type = 0
fee_type = ''
fee_code = ''
fixed_msg_id = 0
msg_level = 0
src_id = '1234'
dest_id = '13800138000'
dest_terminal_type = 0
service_id = ''
tp_pid = 0
tp_udhi = 0
msg_fmt = 15
msg_length = len(msg_content.encode('gbk'))
pk_total = 1
pk_number = 1
tp_udhi = 0
msg = struct.pack('>III10s4s4s3sBBI21s21sBBBBIHBBI', 156 + msg_length, 0x00000004, sequence_id,  # 填充消息头
                  b'source_id', b'1370000000', b'sp_code', b'', msg_level,
                  service_id.encode('gbk'), tp_pid, tp_udhi, msg_fmt, dest_terminal_type,
                  1, '', pk_total, pk_number, registered_delivery, msg_level, fee_type, fee_code,
                  fixed_msg_id, msg_content.encode('gbk'))

# 发送短信
sock.send(msg)
resp_msg = sock.recv(1024)

# 解析CMPP_SUBMIT响应
total_length, command_id, status = unpack('>III', resp_msg[:12])
if command_id == 0x80000004 and status == 0:
    print('Submit OK')
else:
    print('Submit failed')
sock.close()

3. 查询状态报告

下面是查询状态报告的示例代码。在代码中,需要将submit_seq_id替换成实际的提交流水号。

# 获取消息流水号
sequence_id = random.randint(1, 65535)

# 构造CMPP_QUERY消息
query_type = 0
query_code = ''
reserve = ''
msg = struct.pack('>IIIQBB10s32s8s', 57, 0x00000006, sequence_id, submit_seq_id, 
                  query_type, query_code.encode('gbk'), reserve.encode('gbk'), b'')

# 发送查询消息
sock.send(msg)
resp_msg = sock.recv(1024)

# 解析CMPP_QUERY响应
total_length, command_id, status, = unpack('>III', resp_msg[:12])
msg_id, msg_status = unpack('>QH', resp_msg[12:20])

if command_id == 0x80000006 and status == 0 and msg_id > 0:
    print('Message status:', msg_status)
else:
    print('Query failed')
sock.close()

五、总结

CMPP2.0协议是中国移动短信网关中最为常用的一种协议,具有高效、稳定的特点。针对不同的业务需求,可以使用不同的消息类型实现短信的提交、接收、查询等功能。本文通过分析CMPP2.0协议的结构和消息类型,并提供了相应的示例代码,希望能够对广大开发者在进行短信开发时提供一些帮助。