今天在 SOCKET编程时,遇到一个问题。通常 SOCKET的消息包中,需要包含一个长度字段,这个字段存放整个消息包的字节数。
如果消息包采用字符串格式,这个描述长度的字段本身就是一个可变的字符串,它的位数会影响到消息包的长度。例如,我们定义了如下的消息包格式:
# msg_len , msg_content $
这个消息包的格式,非常简单,首先以 '# '字符开头,然后是 msg_len即整个消息包的长度,接着是逗号 ',',接着是消息的内容 msg_content,最后以‘ $’字符结尾。例如,下面就是一个整体长度为 9,消息内容为“ china”的消息包:
#9,china$
那么,编程的时候,如何求出这个 msg_len呢?因为 msg_len本身以字符串表示,随着消息内容的长度变化, msg_len的位数也在变化,由于 msg_len本身也是消息的一部分,因此在计算 msg_len时,还要把 msg_len本身的位数也考虑进去。
试看这两种情况,
- 假如除了 msg_len之外的其余部分的长度为 7,那么 msg_len字段值应为 8。因为 msg_len本身( '8')占一个字符长度,再加上 7,所以长度是8 。
- 假如除 msg_len之外的其余部分的长度为 9,那么 msg_len字段的值应为 11。因为 msg_len本身(‘ 11’)占两个字符长度,再加上 9,所以长度是 11。
设 msg_len的值为 y,设 w(x)表示求取 x的位数,设消息包除了 msg_len之外的其余部分的长度为 x。那么 y满足如下关系:
- 如果 x+w(x)的值的位数,与 x的位数一样,则 y=x+w(x)
- 如果 x+w(x)的值的位数,比 x的位数多 s位,则 y=x+w(y)
第二个式子很难求解,但凭感觉,貌似以下结论成立:
x+w(x)的位数,不可能比 w(x)大1(其等于 w(x)或 w(x)+1)。
以下是我的证明,采用反证法:假设存在一个 x,使 x+w(x)的位数比 w(x)大 1,设:
x=XnXn-1...X1X0, 则有:
XnXn-1...X1X0 + (n+1) >= X'(n+2)X'(n+1)...X'1X'0 =>
max( XnXn-1...X1X0) + (n+1) >= min(X'(n+2)X'(n+1)...X'1X'0) =>
10^(n+1) – 1 + (n+1) >= 10^(n+2) =>
n >= 10^n * 90
显然,这样的 n不可能存在。证明完毕!
基于这个结论,填写消息包的长度时,程序就可以轻松处理了:
- 如果 x+w(x)的值的位数,与 x的位数一样,则 y=x+w(x)
- 如果 x+w(x)的值的位数,比 x的位数大 (由前面的结论,只可能进一位 ),则 y=x+w(x)+1 (因为 x+w(x)已经进了一位,可以证明 x+w(x)+1不会再进一位)。
以下是C语言实现的代码: