回环序号的比较有标准实现

在编程中会出现一类数值比较,数值在一定范围内回环,例如,32bits or 16 bits,需要比较这些序号,以确定是否发生了乱序行为。

逻辑上来看,在回环空间内的数值序号,无始无终,所以,比较大小需要特殊处理,直接用编程语言的比较操作符 ,容易出现逻辑问题!

对于回环序号的比较,实际上在RFC 1982 - Serial Number Arithmetic给予了实施建议,而且从Linux内核的stcp协议栈,也可以将其实现抠出,内核实现确实很精巧。

不过,在rfc规范中指出确实存在一些未定义场景。但是,这类的比较场景是非常稀缺的,所以,内核实现整体上可以是接受的。

同时,内核实现可能刻意仅提供了偏序关系,没有提供对称操作,避免可能二义性编码。

我的直观实现

  • 仅允许一定范围内回环比较
#define SN_THRESHOLD_32 (uint32_t)(0xFFFF)
/*my implemention*/
static inline int TSN_lt_my(uint32_t s, uint32_t t)
{
	return s < t || (s > t && t < (uint32_t)SN_THRESHOLD_32  && (s + SN_THRESHOLD_32) < SN_THRESHOLD_32 && (s + SN_THRESHOLD_32) >= t);
}

static inline int TSN_lte_my(uint32_t s, uint32_t t)
{
	return s == t || TSN_lt_my(s, t);
}

啰嗦了很多 :(

Liniux内核代码–回环序号比较

/* RFC 1982 - Serial Number Arithmetic
 *
 * 2. Comparison
 *  Then, s1 is said to be equal to s2 if and only if i1 is equal to i2,
 *  in all other cases, s1 is not equal to s2.
 *
 * s1 is said to be less than s2 if, and only if, s1 is not equal to s2,
 * and
 *
 *      (i1 < i2 and i2 - i1 < 2^(SERIAL_BITS - 1)) or
 *      (i1 > i2 and i1 - i2 > 2^(SERIAL_BITS - 1))
 *
 * s1 is said to be greater than s2 if, and only if, s1 is not equal to
 * s2, and
 *
 *      (i1 < i2 and i2 - i1 > 2^(SERIAL_BITS - 1)) or
 *      (i1 > i2 and i1 - i2 < 2^(SERIAL_BITS - 1))
 */
 
/*
 * RFC 2960 - SCTP relatives
 *  1.6 Serial Number Arithmetic
 *
 * Comparisons and arithmetic on TSNs in this document SHOULD use Serial
 * Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32.
 */
 
enum {
	TSN_SIGN_BIT = (1<<31)
};


/*previous version of older linux kernel*/
static inline int TSN_lt(uint32_t s, uint32_t t)
{
	return ((s) - (t)) & TSN_SIGN_BIT;
}

static inline int TSN_lte(uint32_t s, uint32_t t)
{
	return ((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT);
}

/*new version of linux kernel*/
static inline int TSN_lt2(uint32_t s, uint32_t t)
{
	return (int32_t)((s) - (t)) < 0;
}

static inline int TSN_lte2(uint32_t s, uint32_t t)
{
	return (int32_t)((s) - (t)) <= 0;
}

/* Compare two SSNs */
/*
 * RFC 2960
 *  1.6 Serial Number Arithmetic
 *
 * Comparisons and arithmetic on Stream Sequence Numbers in this document
 * SHOULD use Serial Number Arithmetic as defined in [RFC1982] where
 * SERIAL_BITS = 16.
 */
enum {
	SSN_SIGN_BIT = (1<<15)
};

static inline int SSN_lt(uint16_t s, uint16_t t)
{
	return ((s) - (t)) & SSN_SIGN_BIT;
}

static inline int SSN_lte(uint16_t s, uint16_t t)
{
	return ((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT);
}

static inline int SSN_lt2(uint16_t s, uint16_t t)
{
	return (int16_t)((s) - (t)) < 0;
}
static inline int SSN_lte2(uint16_t s, uint16_t t)
{
	return (int16_t)((s) - (t)) <= 0;
}

int main(int argc, char* argv[])
{
  printf("Test 32bits TSN wrapped feature ...\n");
  assert(TSN_lte(1, 1));
  assert(TSN_lt(1, 2));
  assert(TSN_lt(1, 0xFFFFFF));
  assert(TSN_lt(0xFFFFFFFF, 1));
  assert(!TSN_lt(0xFFFFFFFF, 0xFFFFFFFE));
  assert(!TSN_lt(0xFFFFFFFF, 0xFFFF0000));
  
  printf("odd behavior, but may accept. the case occurs with little chance\n");
  assert(!TSN_lt(1, 0xFFFFFFFF));
  
  printf("\nTest new version comparing functions ...\n");
  assert(TSN_lte2(1, 1));
  assert(TSN_lt2(1, 2));
  assert(TSN_lt2(1, 0xFFFFFF));
  assert(TSN_lt2(0xFFFFFFFF, 1));
  assert(!TSN_lt2(0xFFFFFFFF, 0xFFFFFFFE));
  assert(!TSN_lt2(0xFFFFFFFF, 0xFFFF0000));
  
  printf("odd behavior, but may accept. the case occurs with little chance\n");
  assert(!TSN_lt2(1, 0xFFFFFFFF));
  
  return 0;
}

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值