码农在处理通讯业务的时候,经常会涉及到数据包的顺序问题。尤其IP网的多态性,UDP数据包在发送到接收的过程中,无法做到先发先收(TCP协议内部实现了滑动窗口下的重新排序),在很多情况下都需要自己来重新排序规整数据。

// ShiftWin 滑动窗口,UDP导致的数据包顺序被打乱恢复

type Node struct{

serial int // 节点序号

cTime int64 // 时间戳

data []byte // 数据内容

next *Node

prev *Node

}

type ShiftWin struct {

head *Node // 插入时确保从小到大,翻转出口

tail *Node // 数据有时间,正常是有序,所以从后往前找,可以减少消耗

outChan chan []byte // 超时及溢出数据出口

count int

size int

timeout int64

}

// 超时检测

func timeoutdetect(self *ShiftWin){

// 超时检测

for self.timeout>0 {

if(self.count>0){

if(time.Now().Unix()-self.head.cTime > self.timeout){

self.outChan <-self.head.data

self.head=self.head.next

if self.head != nil{

self.head.prev=nil

self.count–

}else{

self.count=0

}

}

}

time.Sleep(time.Second)

}

}

func newShifWin(rch chan []byte, size int,timeout int64) *ShiftWin{

sw:=ShiftWin{

size: size,

timeout: timeout,

outChan: rch,

}

// 创建超时检测协程?每个元素/一个滑动窗口一个协程

go timeoutdetect(&sw)

return &sw

}

func serialBefore(seq1 int,seq2 int) bool{

interval:=seq2-seq1

if (interval>0 && interval<32768)||(interval < (-32768)){

return true

}

return false

}

func cleanShiftWin(self *ShiftWin){

for self.head!=nil {

fmt.Println(“Node:”,string(self.head.data))

self.head=self.head.next

}

}

func InsertShiftWin(self *ShiftWin,serial int,data []byte){

//fmt.Println(“Append:”,serial,”Count:”,self.count)

node:=Node{

serial:serial,

data:data,

cTime:time.Now().Unix(),

}

if self.count==0{

self.count=1

self.head=&node

self.tail=&node

return

}

if(self.count<self.size){

self.count++

}else{

// 达到容量,弹出最前面的数据

self.outChan<-self.head.data

self.head=self.head.next

self.head.prev=nil

}

if serialBefore(self.tail.serial,serial){

//fmt.Println(“Append tail”)

node.prev=self.tail

self.tail.next=&node

self.tail=&node

}else{

cur:=self.tail.prev

for (cur!=nil)&&serialBefore(serial,cur.serial){

// 找到插入点

cur=cur.prev

}

if cur!=nil{

//fmt.Println(“Append data”,serial)

cur.next.prev=&node

node.next=cur.next

cur.next=&node

node.prev=cur

}else{ // 头部插入

//fmt.Println(“Append Head”)

node.next=self.head

self.head.prev=&node

self.head=&node

}

}

}

代码堆出来,有兴趣的可以自己去玩玩。其实发现无论用哪种编程语言,编程方法都是一样的,思想决定代码。顺带谴责一下用代码量来考核编程工作量的行径。诚然我也不知道该如何去衡量一个程序员的工作量。

写程序有时候就是在做创作,好的思路和实现,会带来发自内心的愉悦。