文章标题:采用最新版本的UDP功能,实现多个平台之间的全局锁 |
文章作者:bluesen |
发表时间:2012-3-3 14:17:35 |
内容:
一、基本原理: 多个平台之间也可能需要全局锁,比如多台机器同时预测外呼,那么不能取到相同的一批号码。全局锁的实现方法是: 在其中一台机器部署一个虚拟线路专门运行管理令牌的脚本。 每个平台都可以运行1个客户端脚本,在需要访问独占资源时,向服务程序申请令牌,资源访问完毕后,再交回令牌。 令牌可以按任务进行编号,即不同的任务不同的锁。 下面的程序考虑了UDP的不可靠性,客户端在没有收到响应时会重复地发送请求。 二、服务端脚本:TokenRing.bss tonkenPort = 7102; hd = UdpOpen(tonkenPort); if( hd<0 ) { DispInfo(0, "UdpOpenErr:"+hd); return(0); } // 请求数据包结构: cmdcid // cmd: GET - 请求获取令牌,cid为参数 // PUT - 请求交还令牌,cid为参数 // 响应数据包结构: Acmdcid // A: 0不成功,1成功 // cmd: GET - 响应get请求 // PUT - 响应put请求 // cid: 原样返回 tokens = 0; count = 0; buff = ""; ip = ""; port = 0; while(1) { ret = UdpRecv(hd, ip, port, buff); if( ret>0 ) { DispInfo(0, ret); DispInfo(1, port); DispInfo(2, buff); frm = ip+":"+port; cmd = Substr(buff, 0, 3, 0); cid = Substr(buff, 3, 100, 0); if( cmd=="GET" ) // 取令牌 { val = tokens[cid]; if( val==NULL || val==frm ) { tokens[cid] = frm; a = "1"; } else a = "0"; UdpSend(hd, ip, port, a+cmd+cid); } else if( cmd=="PUT" ) // 还令牌 { val = tokens[cid]; if( val==frm ) { tokens[cid] = NULL; a = "1"; } else a = "0"; UdpSend(hd, ip, port, a+cmd+cid); } else if( cmd=="EXT" ) // 退出 break; } // Sleep(0.05); } OnSysQuit(); UdpClose(hd); return(0); 三、客户端脚本和测试程序: GetToken.bss // 获取令牌的客户端函数 tonkenIp = "127.0.0.1"; tonkenPort = 7102; myPort = 7103+_lineNo; function SendTokenReq(hd, cmd, cid) { ret = -1; UdpSend(hd, tonkenIp, tonkenPort, cmd+cid); t1 = GetTick(0); while(1) { n = UdpTest(hd); if( n>0 ) { buff = ""; ip = ""; port = 0; ret = UdpRecv(hd, ip, port, buff); if( ret>0 ) { DispInfo(2, buff); a = Substr(buff, 0, 1, 0); cmd2 = Substr(buff, 1, 3, 0); cid2 = Substr(buff, 4, 100, 0); if( cmd2==cmd && cid2==cid ) { ret = Int(a, 0); break; } else ret = -2; // break; } } else if( n<0 ) { ret = -3; break; } t2 = GetTick(0); if( t2-t1>210 ) break; Sleep(0.05); } return(ret); } function ProcToken(hd, cmd, cid) { for(i=0; i<6; i++) { ret = SendTokenReq(hd, cmd, cid); if( ret>=0 ) break; } return(ret); } // ------------------- // 暴露的接口: // 初始化 function InitToken(port) { hd = UdpOpen(port); if( hd<0 ) { DispInfo(0, "UdpOpenErr:"+hd); return(-1); } return(hd); } // 关闭 function CloseToken(hd) { if( hd ) { UdpSend(hd, tonkenIp, tonkenPort, "EXT123"); UdpClose(hd); hd = 0; } } // 加锁 function LoackToken(hd, cid) { for(i=0; i<35; i++) { ret = ProcToken(hd, "GET", cid); if( ret==1 ) break; Sleep(0.1); } return(ret); } // 解锁 function UnloackToken(hd, cid) { ret = ProcToken(hd, "PUT", cid); return(ret); } // ----------------------------- // 测试脚本 hd = InitToken(myPort); cid = "1234567890-abcdefg-hello-word"; while(1) { len = KeysLen(0); if( len<1 ) { Sleep(0.05); continue; } s = ""; PcGetKeys(s, 1, 3); if( s=="" ) continue; if( s=="l" ) // lock { t1 = GetTick(0); ret = LoackToken(hd, cid); t2 = GetTick(0); DispInfo(0, ret); DispInfo(1, t2-t1); } else if( s=="u" ) // unlock { t1 = GetTick(0); ret = UnloackToken(hd, cid); t2 = GetTick(0); DispInfo(0, ret); DispInfo(1, t2-t1); } else if( s=="q" ) // quit { CloseToken(hd); break; } Sleep(0.1); } OnSysQuit(); CloseToken(hd); return(0); |
已有回复: |
回复如下