一、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协议的结构和消息类型,并提供了相应的示例代码,希望能够对广大开发者在进行短信开发时提供一些帮助。