思华CP接口Socket协议
2007-6-20
1. 首先需要确认你拿到的是这个版本的协议,其它版本我不敢保证能行.
2. 思华定义的socket发送包我是头是遇到,搞不懂怎么回事,调试了三天,终于弄明白他是啥意思
3. Head 1字节 (Byte类型), Len 2字节 (Int16、Short类型,具体看语言决定,我这里列举的是.Net和VB里的), Context 具本看办议规定
4. 我用VB.Net 2.0开发,将上面的定义写成结构,再将结构转成Byte数组,现在网上有.Net下的转换函数(Struct2Bytes),可以自己搜一下,CSDN里也有。现在我们来看看.Net下对思华登录结构的定义:
#Region "定义登录"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure Login
Public Head As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public Len() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
Public Account() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public Password() As Byte
End Structure
#End Region
这里有个问题。 Head 是Byte类型的,在转换后必须还是Byte类型,而且是一字节。比如说Head=1 那么Socket的发送Buff头一字节就是1, 而并不是ASCII码的49。
Len就更奇怪了。在Socket的发送Buff里占索引号的1 2位(也就是两字节)。 如果你直接把Len声明为Int16、Short或其它两字节的整型话,经结构转为Byte数组的结果是三位。比如Len=60,Buff看到的就是 0 60 0,那么登录的发送Buff那就是
1
0
60
0
X
X
X
X
这样的话传过去就不对,而且最明显的就是调用同步Socket的Send方法是会阻塞几秒钟,如要按正确的方式发送不会造成阻塞,我想他那边应该是异步接收。这就奇怪了,.Net 和 VC写的结构转成Buff都是这样,那么很明显就是写协议的人规定有问题,这里我不禁要狠狠B4一下。
所以我上面在登录结构中定义的Len写的是二字节的Byte,因为这里需要手动转换。而且转换还必须是高低位相反,简直没搞懂。比如 Len = 60那么Buff里就应该是
1
60
0
一般的程序处理出来应该是
1
0
60
这就太扯巴子了,所以我用了VB里的特有的Redim语法转换一下
Dim Len() As Byte
Len = System.Text.Encoding.ASCII.GetBytes(Chr(60))
Redim Preserve Len(1)
这时Len(0) = 60, Len(1)=0
其实也不用这么麻烦,因为结构发送一般都是定长,所以你也可以直接给Len数组赋值。
但如果长度超出128的话也会有问题,所以就以满256进1的原则来手动算吧,反正他定长,一般不会变。
比如发送短信的包是550,那么长度应该是
Len(0) = 38
Len(1) = 2
256*2+38=550,清楚了吗。2就是Len(1)里的
接下来就是Context,这个比较简单,转化为一般的ASCII数组就行
System.Text.Encoding.ASCII.GetBytes("思华写的很laji")。
接收思华主控发往CP的时候。
Context可以用Char()来替代,这样省去一道自行将Byte()转为String的工序
我的接收登录响应的结构定义
#Region "定义登录响应"
<StructLayout(LayoutKind.Explicit, CharSet:=CharSet.Ansi)> _
Public Structure LoginReq
<FieldOffset(0)> Public Head As Byte
<FieldOffset(1)> Public Len As Int16
<FieldOffset(3)> Public Context As Char
End Structure
#End Region
'----------------------------
以下附上我的一个封装结构定义类 .Net 2.0的
(MsgStructure.vb)
Imports System.Runtime.InteropServices
#Region "定义登录"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure Login
Public Head As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public Len() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
Public Account() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public Password() As Byte
End Structure
#End Region
#Region "定义登录响应"
<StructLayout(LayoutKind.Explicit, CharSet:=CharSet.Ansi)> _
Public Structure LoginReq
<FieldOffset(0)> Public Head As Byte
<FieldOffset(1)> Public Len As Int16
<FieldOffset(3)> Public Context As Char
End Structure
#End Region
#Region "定义下行结构"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure Send
Public Head As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public Len() As Byte
Public Context As SendContext
End Structure
#End Region
#Region "定义下行内容体"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure SendContext
'(移动CMPP,电信SMGP,联通SGIP,网通SNGP)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
Public MsgKind() As Byte
'内部信息标识
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public LinkNo() As Byte
'相同Msg_Id的信息总条数,默认为1
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public PkTotal() As Byte
'相同Msg_Id的信息序号,默认为1
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public PkNumber() As Byte
'计费用户类型
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public FeeUserType() As Byte
'业务代码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
Public ServiceCode() As Byte
'计费类型
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=6)> _
Public FeeType() As Byte
'费用代码(1元用100表示)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=6)> _
Public FeeCode() As Byte
'包月费/封顶费
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=6)> _
Public FixedFee() As Byte
'赠送费用
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=6)> _
Public GivenValue() As Byte
'收费用户号码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _
Public FeeTerminalID() As Byte
'收费用户号码类型,默认为0
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public FeeTerminalIDType() As Byte
'信息格式 (15代表包含汉字,一般用15)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public MsgFmt() As Byte
'内部的有效期时间 (过期时间)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=19)> _
Public ValidTime() As Byte
'内部的执行时间 (定时发送)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=19)> _
Public AtTime() As Byte
'发送号码(此处为SP的端口+长号码)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=21)> _
Public SrcID() As Byte
'接收号码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _
Public DestID() As Byte
'接收号码类型, 收费用户号码类型(0真实号码,1伪码)默认为0
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public DestIDType() As Byte
'信息内容
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=255)> _
Public MsgContent() As Byte
'上行信息的LINKID,无上行不填
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public LinkID() As Byte
'短信类型
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public MsgType() As Byte
'SP代码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
Public SPCode() As Byte
'ServiceID
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
Public ServiceID() As Byte
End Structure
#End Region
#Region "定义上行内容体"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure ReceiveUpContext
'内部信息标识
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public LinkNo() As Char
'MsgID
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public MsgID() As Char
'接收号码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=21)> _
Public DestID() As Char
'接收号码类型(0、真实号码,1、伪码)
Public DestIDType As Char
'发送号码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _
Public SrcID() As Char
'发送号码类型(0、真实号码,1、伪码)
Public SrcIDType As Char
'业务代码
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public ServiceCode() As Char
'信息格式 (15代表包含汉字)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public MsgFmt() As Char
'信息内容
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=255)> _
Public MsgContent() As Char
'点播业务使用的LinkID,非点播类业务的MT流程不使用该字段
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=50)> _
Public LinkID() As Char
End Structure
#End Region
#Region "心跳下行结构"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure HeartJump
Public Head As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public Len() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public Context() As Byte
End Structure
#End Region