socketref,再见!高德

https://github.com/adoggie

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  246 Posts :: 4 Stories :: 312 Comments :: 0 Trackbacks

常用链接

留言簿(54)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜


采用Ice编写的Rpc服务应用,endpoint部署在5173.com的游戏做单PC上,sync_server部署在游戏运维网管机器上。
sync_server与endpoint是1对多的形态部署。某一款游戏做了修改或者逆向代码有了修改,通过sync_server将新增部分同步到几百台endpoint游戏主机。
类能类似 EMC的 Networker 同步软件。
文件校验使用md5

通信接口定义sync.ice(IDL)
  1 
  2 #ifndef _SYNC_ICE
  3 #define _SYNC_ICE
  4 
  6 module games {
  7 
  8 dictionary<string,string>    HashValueSet;
  9 dictionary<string,string>    ReturnValueT;
 10 sequence<byte>                 StreamDataT;
 11 sequence<string>            StringListT;
 12 sequence<HashValueSet>    HashValueListT;
 13 sequence<int>                    IntListT;
 14 sequence<StringListT>    StringListListT;
 15 
 16 
 17 interface IService{
 18     void        invokeOneway(HashValueSet value,StreamDataT stream);
 19     string    getSequence();
 20     string    getType();             // das ,cmc,
 21     string    getId();                //service module id
 22     int     getTimestamp();        //获取系统时钟  1970之后秒数
 23   string getVersion();      //系统版本 2009.12.27
 24 };
 25 
 26 
 27 struct FileEntryT{
 28     string    filename;    //文件不能携带远端的存储路径
 29     int         size;
 30     int         timestamp;
 31     string     digest;
 32 };
 33 sequence<FileEntryT>    FileEntryListT;
 34 
 35 
 36 interface ISyncEndpoint extends IService{
 37     /***************************************************
 38         @methond: getFileDescList()
 39         @params:  读取指定目录文件描述信息
 40         @return: 
 41             {'succ':true/false,'errmsg':xxx}
 42     ****************************************************/
 43     FileEntryListT getFileDescList(string path);
 44     
 45     /***************************************************
 46         @methond: getFileDigest()
 47         @params:  file - 远程文件名称 
 48         @return: 
 49             {'succ':true/false,'errmsg':xxx,'digest':''}
 50     ****************************************************/
 51     ReturnValueT    getFileDigest(string file);
 52     /***************************************************
 53         @methond: Start()
 54         @params:
 55                 file - 远程文件名称
 56         @return: 
 57             {'succ':true/false,'errmsg':xxx}
 58     ****************************************************/
 59     ReturnValueT     syncFileStart(string file);
 60     /***************************************************
 61         @methond: Data()
 62         @params: []
 63         @return: 
 64             {'succ':true/false,'errmsg':xxx}
 65     ****************************************************/
 66     ReturnValueT     syncFileData(string bytes);
 67     /***************************************************
 68         @methond: End()
 69         @params:
 70         @return: 
 71             {'succ':true/false,'digest':xxx,'errmsg':xxx}
 72             完成之后是否计算digest
 73     ****************************************************/
 74     ReturnValueT     syncFileEnd();
 75     
 76     /***************************************************
 77         @methond: launchApp()
 78         @params:
 79             {'app':'path','param':'xxx'}
 80         @return: 
 81             {'succ':true/false,'errmsg':xxx}
 82             运行进程
 83     ****************************************************/
 84     ReturnValueT launchApp(HashValueSet params);
 85     
 86     /***************************************************
 87         @methond: deleteFile()
 88         @params:
 89             file - 文件名称或者目录 
 90         @return: 
 91             {'succ':true/false,'errmsg':xxx}
 92             运行进程
 93     ****************************************************/
 94     ReturnValueT    deleteFile(string file);
 95     
 96     /***************************************************
 97         @methond: terminateGame()
 98             停止游戏运行 
 99         @params:
100             game - 游戏目录名称 (英文)
101         @return: 
102             {'succ':true/false,'errmsg':xxx}
103     ****************************************************/
104     ReturnValueT    terminateGame(string game);
105     
106     /***************************************************
107         @methond: launchGame()
108             加载游戏运行 
109         @params:
110             game - 游戏目录名称 (英文)
111         @return: 
112             {'succ':true/false,'errmsg':xxx}
113     ****************************************************/
114     ReturnValueT    launchGame(string game);
115     
116     /***************************************************
117         @methond: executeBatchFile()
118             执行远程批处理文件
119         @params:
120             file - 文件全路径
121         @return: 
122             {'succ':true/false,'errmsg':xxx}
123             运行进程
124     ****************************************************/
125     ReturnValueT executeBatchFile(string file);
126     
127     /***************************************************
128         @methond: killProcessByName()
129         停止指定名称的进程
130     ****************************************************/
131     ReturnValueT killProcessByName(string procname);
132     
133     /***************************************************
134         @methond: startUpdate()
135         启动endpoint的自我更新
136         endpoint应当加载 update.exe ,然后令自己退出
137         update.exe的位置在jerray.conf配置
138     ****************************************************/
139     ReturnValueT startUpdate();
140   
141   //读取远端指定文件数据到本地,适合小文件
142   StreamDataT getRemoteFile(string remotefile);
143   //读取远端文件信息
144   FileEntryT getFileDesc(string remotefile);
145   //读取远端文件,offset-偏移位置,size-读取数据大小
146   StreamDataT getRemoteFileData(string remotefile,int offset,int size);
147   
148   //关闭endpoint服务
149   void shutdown(); 
150       
151 };
152 };
153 
154 
155 #endif
156 
157 

endpoint.conf
1 server.id=GEP-1
2 SyncEndPoint.Endpoints=tcp -5000
3 endpoint_updir=c:/ep_update
4  
5 Ice.Override.Compress=0
6 Ice.Compression.Level=5
7 Ice.MessageSizeMax=50000

server.conf
 1 server.id=SERVER-1
 2 SyncEndPoint.Endpoints=tcp -5000
 3 
 4 endpoint.servant=endpoint
 5 endpoint.port=5000
 6 endpoint_hosts=hosts.list
 7 #logfile=abc.log
 8 
 9 games=A#,B                        #游戏列表
10 A.path=c:/a/                 #本地游戏数据目录
11 A.dest_path=c:/a2            #远端游戏存储数据目录 
12 A.launch.app=                    #完成更新执行命令
13 A.launch.params=            #执行远程命令携带的参数
14 
15 B.path=c:/audio
16 B.dest_path=d:/audio_remote
17 game_hosts=hosts.list
18 workthread.num=1        #并发传送工作线程数量
19 
20 Ice.Warn.Connections=1
21 Ice.ThreadPool.Server.Size=20
22 Ice.ThreadPool.Server.SizeMax=100
23 Ice.Override.Compress=0
24 Ice.Compression.Level=5
25 Ice.MessageSizeMax=50000
26 Ice.Override.ConnectTimeout=100
27 

endpoint.py 游戏主机服务程序
  1 # -*- coding:utf-8 -*-
  2 
  3 # revisions:
  4 # 2009.11.05 scott
  5 # 1. created
  6 #    2. 实现c++版本全部接口,保持调用一致性
  7 # 2009-12.26 scott
  8 # 1. 支持升级: 创建c:/ep_update目录存放更新文件,当升级时将新的endpoint程序传输到目标主机的d:/ep_update下
  9 #              启动ep_update/update.exe,然后endpoint.exe自动退出; update将新的程序文件覆盖掉原来的endpoint文件
 10 #                            最后启动endpoint.exe,update.exe自动退出 
 11 
 12 
 13 # 2009.12.27 scott
 14 # 1. 为支持endpoint的升级,目前解决方法是在syncserver端主动停止endpoint进程,然后再加载新的enpoint
 15 #            这就要求endpoint退出之前加载新的endpoint进程,新的进程必须delay加载,因为端口会产生冲突
 16 
 17 import sys,os
 18 #sys.path.insert(0,'C:\Ice-3.3.1-VC90\python')
 19 #sys.path.append('../lib')
 20 
 21 import traceback,threading,time,struct,os,os.path,shutil,distutils.dir_util,array,base64,zlib,struct,binascii
 22 import copy,socket,select,hashlib,win32process,win32api,win32con,re
 23 #import win32com.client
 24 #from xml.dom import minidom
 25 import codec,log,config
 26 
 27 import Ice
 28 
 29 Ice.loadSlice('-I../idl -I../idl/slice ../idl/sync.ice')
 30 from games  import *
 31 
 32 ##############################################################
 33 VERSION='v0.2.0 2009.12.27 scott'
 34 
 35 
 36 class SyncServiceEndpoint(ISyncEndpoint):
 37     def __init__(self,app):
 38         self._app = app
 39         self._fwh = None
 40         self._seqno = 0
 41         pass
 42     def invokeOneway(self, value, stream, current=None):
 43         pass
 44     
 45     def getSequence(self, current=None):
 46         self._seqno+=1
 47         return self._seqno
 48     
 49     def getType(self, current=None):
 50         return 'GRT_UPDATER'
 51     
 52     def getId(self, current=None):
 53         return self._app.getPropertyValue('server.id')
 54     
 55     def getTimestamp(self, current=None):
 56         return int(time.time())
 57     
 58     def getVersion(self,current=None):
 59         return VERSION
 60     
 61     #--------------
 62     #获取指定路径下所有文件信息
 63 
 64     def getFileDescList(self, path, current=None):
 65         rs=[]
 66         try:
 67             print "calc digest and return"
 68             #print ">>getFileDescList:%s"%path
 69             for root, dirs, files in os.walk(path, topdown=False):
 70                 for name in files:
 71                     file = os.path.join(root, name)
 72                     fe = FileEntryT()
 73                     fe.filename = file.lower()
 74                     fe.size = os.stat(file).st_size
 75                     fe.timestamp = 0
 76                     fe.digest = codec.calcFileMd5Digest(file)
 77                     rs.append(fe)                
 78         except:
 79             print traceback.print_exc()
 80             pass
 81         #print str(rs)
 82         
 83         return rs
 84     
 85     #取单个文件的摘要信息
 86     def getFileDigest(self, file, current=None):
 87         digest=''
 88         try:
 89             digest = codec.calcFileMd5Digest(file)
 90         except:
 91             pass
 92         return digest
 93     
 94     
 95     #文件同步开始
 96     def syncFileStart(self, file, current=None):
 97         r={}
 98         print "prepare file:",file
 99         filename = file
100         #deep create dir
101         r['succ'= 'true'
102         try:
103             filename = os.path.normpath(filename)
104             path = os.path.dirname(filename)
105             #file = os.path.basename(filename)
106             #print "path:",path
107             #distutils.dir_util.create_tree(path,file)
108             #distutils.dir_util.mkpath(path)
109             self.mkpath(path)
110             self._fwh = open(filename,'wb')
111         except:
112             #print traceback.print_exc()
113             r['succ']='false'
114         return r
115     
116     def syncFileData(self, bytes, current=None):
117         r={'succ':'true'}
118         try:
119             self._fwh.write(bytes)
120             self._fwh.flush()
121         except:
122             r['succ']='false'
123         return r
124     
125     def syncFileEnd(self,current=None):
126         r={'succ':'true','digest':''}
127         try:
128             self._fwh.close()                                
129         except:
130             r['succ']='false'
131         return r
132     
133     #执行本地程序
134     def launchApp(self, params, current=None):
135         try:
136             print u"创建进程:%s"%params['app']
137             print params
138             #win32process.CreateProcess(params['app'], params['param'], None , None , 0 ,win32process.CREATE_NO_WINDOW , None , None ,
139             win32process.CreateProcess(None,params['app']+' '+params['param'], None , None , 0 ,win32process.CREATE_NEW_CONSOLE , None , None ,
140             
141                 win32process.STARTUPINFO())    
142         except:
143             print traceback.print_exc()
144     
145     def deleteFile(self, file, current=None):
146         r={'succ':'true'}
147         try:
148             if os.path.isdir(file):
149                 distutils.dir_util.remove_tree(file)
150             if os.path.isfile(file):
151                 os.remove(file)
152         except:
153             r['succ']='false'
154         return r
155     
156     def terminateGame(self, game, current=None):
157         r={'succ':'true'}
158         try:            
159             #file = "%s/RobotSetting.xml"%game
160             #xmldoc = minidom.parse(file)
161             #root = xmldoc.documentElement
162             #node = root.getElementsByTagName('GameProcess')
163             #n =root.getElementsByTagName('RobotPath')            
164             #path = root.getElementsByTagName('RobotPath').nodeName #nodeName,nodeType
165             
166             conf = config.SimpleConfig()
167             if not conf.open("%s/RobotSetting.conf"%game):
168                 r['succ']='false'
169                 r['errmsg']='game config lost!'
170                 return r
171             s = conf.getPropertyValue('GameProcess')
172             processes  = s.split(',')            
173             for p in processes:
174                 pid = self.getProcessIdByName(p)
175                 if pid != -1:
176                     print "Kill Process:(%s)%s"%(pid,p)
177                     self.killProcess(pid)
178         except:
179             print traceback.print_exc()
180             r['succ']='false'
181         return r
182     
183     #加载游戏
184     #读取游戏目录下的 RobotSetting.xml 配置信息
185     #
186     def launchGame(self, game, current=None):
187         r={'succ':'true'}
188         #self.terminateGame(game)    #停止游戏运行 
189         try:
190             #file = "%s/RobotSetting.xml"%game
191             #xmldoc = minidom.parse(file)
192             #root = xmldoc.documentElement            
193             #path = "%s/%s"%(game,root.getElementsByTagName('RobotPath').nodeName.strip()) # nodeName,nodeType
194             conf = config.SimpleConfig()
195             if not conf.open("%s/RobotSetting.conf"%game):
196                 r['succ']='false'
197                 r['errmsg']='game config lost!'
198                 return r
199             s = conf.getPropertyValue('RobotPath')
200             path = "%s/%s"%(game,s)
201             print 'Execute file:',path
202             win32process.CreateProcess(path, '', None , None , 0 ,win32process.CREATE_NO_WINDOW , None , None ,
203                 win32process.STARTUPINFO())            
204         except:
205             #print traceback.print_exc()
206             r['succ']='false'
207             #r['errmsg'] = traceback.print_exc()
208         return r
209 
210     #执行批处理文件
211     def executeBatchFile(self,file,current=None):
212         r={'succ':'true','verbose':''}
213         try:
214             print 'Exceute Batch File:',file
215             r['verbose']=os.popen("%s"%file).read()
216         except:
217             r['succ']='false'
218         return r
219     
220     #杀掉制定进程名称
221     def killProcessByName(self,procname,current=None):
222         try:
223             pid = self.getProcessIdByName(procname)
224             if pid != -1:
225                 print "Kill Process:(%s)%s"%(pid,procname)
226                 self.killProcess(pid)
227         except:
228             print traceback.print_exc()
229     
230     #开始更新
231     def startUpdate(self,current=None):        
232         try:
233             upfile = os.path.normpath( self._app.getPropertyValue('endpoint_updir')+'/update.exe')
234             print u'启动更新进程:%s'%upfile
235             win32process.CreateProcess(upfile, '', None , None , 0 ,win32process.CREATE_NO_WINDOW , None , None ,
236                 win32process.STARTUPINFO())        
237             sys.exit(0)    
238         except:
239             print traceback.print_exc()
240     
241     def shutdown(self,c=None):
242         print u'停机'
243         sys.exit(0)
244     
245     def getRemoteFile(self,remotefile,c=None):
246         pass
247     
248     def getFileDesc(self,remotefile,c=None):
249         pass
250     
251     def getRemoteFileData(self,remotefile,offset,size,c=None):
252         pass
253     
254     #---------------------------------------
255     def mkpath(self,path):
256         try:
257             #print '>>',path
258             ls = path.split('\\')
259             dirname = ls[0]
260             for n in range(1,len(ls)):
261                 dirname = dirname+"\\"+ls[n]
262                 #print 'make dir:',dirname
263                 try:
264                     os.mkdir(dirname)
265                 except:pass
266         except:
267             print traceback.print_exc()
268             return False
269         return True
270     
271     #def getProcessIdByName(self,pname):
272     #    pid = -1
273     #    pname = pname.strip()
274     #    WMI = win32com.client.GetObject('winmgmts:')
275     #    rs = WMI.ExecQuery("select * from Win32_Process where name ='%s'"%pname)
276     #    for r in rs: #.ProcessId,n.Name
277     #        pid = r.ProcessId
278     #        break
279     #    return pid
280     
281     #def getProcessIdByName(self,pname):
282     #    pid = -1
283     #    pname = pname.strip()
284     #    print pname
285     #    allPIDs = win32process.EnumProcesses()
286     #    
287     #    for PID in allPIDs:
288     #        try:
289     #            hProcess = win32api.OpenProcess(win32con.PROCESS_TERMINATE, False, PID)
290     #            hProcessFirstModule = win32process.EnumProcessModules(hProcess)[0]
291     #            currentprocessname = os.path.split(win32process.GetModuleFileNameEx(hProcess, hProcessFirstModule))[1]
292     #            #print currentprocessname
293     #            if pname.lower() == currentprocessname.lower():
294     #                pid = PID
295     #        except Exception, e:
296     #            pass#print traceback.print_exc()
297     #    return pid
298     
299     def getProcessIdByName(self,pname):
300         pid = -1
301         pname = pname.strip().lower()
302         
303         try:
304             lines = os.popen('tasklist').read()
305             lines = lines.split('\n')
306             #print len(lines)
307             #return 
308             #fp = open('c:/tasklist.txt','w')
309             #fp.write(lines)
310             #fp.close()
311             #fp = open('c:/tasklist.txt')
312             #lines = fp.readlines()
313             #fp.close()
314             for line in lines:
315                 try:
316                     line = line.strip().lower()
317                     pids = re.findall("^%s\s+(\d+).*"%pname,line)                    
318                     if len(pids):
319                         pid = pids[0]
320                     
321                 except:pass
322         except:
323             pass
324         print "getProcessIdByName(%s)=>%s"%(pname,pid)
325         return pid
326     
327 #检测进程名是否存在 
328     def isProcessExist(self,pname):
329         r=True
330         if self.getProcessIdByName(pname) == -1:
331             r = False
332         return r
333     
334     def killProcess(self,pid):
335         try:
336             hProcess = win32api.OpenProcess(win32con.PROCESS_TERMINATE, False, int(pid))
337             win32api.TerminateProcess(hProcess,0)
338         except:
339             print traceback.print_exc()
340         
341         #os.system("taskkill /F /PID %s"%pid)
342 #################################################
343 #################################################
344 
345 class sepApp(Ice.Application):
346     def    __init__(self):
347         self._conf = config.SimpleConfig()        
348         self.service = SyncServiceEndpoint(self)
349     
350     def test(self):
351         #print self.service.getProcessIdByName('Insight3.Exe')
352         #print self.service.terminateGame('c:/aaa')
353         #print self.service.launchGame('c:/a')
354         #print self.service.deleteFile('c:/a/NOTEPAD.EXE')
355         #self.service.getProcessIdByName('hh.exe')
356         #self.service.killProcess(2968)
357         pass
358     
359     def run(self, args):
360         #self.test()
361         #return 0
362         #self._adapter = self.communicator().createObjectAdapterWithEndpoints("SyncEndPoint")
363         self._log = log.Logger(self.getPropertyValue('logfile','endpoint.log'))
364         self._adapter = self.communicator().createObjectAdapter("SyncEndPoint")
365         self._adapter.add( self.service, self.communicator().stringToIdentity('endpoint')) #服务入口接口对象 
366         self._adapter.activate()
367         self._log.debug( 'endpoint (%s) service start!'%VERSION)
368         self.communicator().waitForShutdown()
369         return 0
370 
371     def getPropertyValue(self,propName,default=''):
372         return self.communicator().getProperties().getPropertyWithDefault(propName,default)
373     
374     def getPropertyIntValue(self,propName,default=0):
375         try:
376             default = int(default)
377         except:
378             default = 0 
379         return self.communicator().getProperties().getPropertyAsIntWithDefault(propName,default)
380     
381 
382 
383 ##############################################################
384 ##############################################################
385 
386 if __name__=='__main__':
387     #print win32con.PROCESS_TERMINATE
388     #ps = os.popen('tasklist').read()
389     #f = open('c:/dump.txt','w')
390     #f.write(ps)
391     #f.close()
392     #print ps
393     #sys.exit()
394     if len(sys.argv) >=3:
395         if sys.argv[1=='-d':
396             delay = 5
397             try:
398                 delay = int(sys.argv[2])
399             except:
400                 pass
401             time.sleep(delay) #延迟
402     #print sys.argv
403     server = sepApp()
404     sys.exit(server.main(sys.argv, "../etc/jerry.conf"))
405     
406     
407         
408     

sync_server.py 网管服务程序
  1 # -*- coding:utf-8 -*-
  2 
  3 # revisions:
  4 # 2009.11.05 scott
  5 # 1. created
  6 
  7 # 2009.12.26 scott created
  8 
  9 # 2010.1.26 scott
 10 # 1. 增加远程文件比对的操作接口
 11 
 12 import sys,os
 13 sys.path.insert(0,'C:\Ice-3.3.1-VC90\python')
 14 sys.path.append('../lib')
 15 import traceback,threading,time,struct,os,os.path,shutil,distutils.dir_util,array,base64,zlib,struct,binascii
 16 import copy,socket,select,getopt
 17 import codec,log,config
 18 
 19 import Ice
 20 
 21 Ice.loadSlice('-I../idl -IC:\Ice-3.2.1\slice ../idl/sync.ice')
 22 from games  import *
 23 
 24 DELIMITER='*'
 25 ##############################################################
 26 
 27 class syncApp(Ice.Application):
 28     def    __init__(self):
 29         self._conf = config.SimpleConfig()
 30         
 31         
 32         self._mtx_hosts= threading.Lock()
 33         self._game_hosts=[]
 34         
 35         self._gamelist=[]
 36         ################################
 37         
 38         
 39     def init_hosts(self):
 40         #初始化游戏客户机信息
 41         #try:
 42         #    fp = open('../etc/hosts.list','r')
 43         #    lines = fp.readlines()
 44         #    fp.close()
 45         #    for l in lines:
 46         #        host,game = l.strip().split(',')
 47         #        host = host.strip()
 48         #        game = game.strip()
 49         #        if len(host) == 0 or len(game)==0:
 50         #            continue
 51         #        self._game_hosts.append({'host':host,'game':game})
 52         #except:
 53         #    print 'Error: read game host failed!'
 54         #    return False
 55         return True
 56     
 57     #初始化游戏目录 
 58     def init_games(self):
 59         self._log = log.Logger(self.getPropertyValue('logfile','server.log'))
 60         self._errlog = log.Logger(self.getPropertyValue('errlogfile','error.log'))
 61         #names = self.getPropertyValue('games')
 62         #games=names.split(',')
 63         #for g in games:
 64         #    g = g.strip()
 65         #    if len(g) == 0:
 66         #        continue
 67         #    gi = gameInfoT()
 68         #    gi.name = g
 69         #    gi.path = self.getPropertyValue("%s.path"%g).strip().lower()
 70         #    gi.dest_path = self.getPropertyValue("%s.dest_path"%g).strip().lower()
 71         #    gi.launch_app = self.getPropertyValue("%s.launch.app"%g)
 72         #    gi.launch_params = self.getPropertyValue("%s.launch.params"%g)
 73         #    self._gamelist.append(gi)
 74     
 75     def getLogger(self):
 76         return self._log
 77 
 78     def getErrLogger(self):
 79         return self._errlog
 80     
 81     def getGameList(self):
 82         return self._gamelist
 83     
 84     #return host info ,else none
 85     def get_gamehost(self):
 86         host =None
 87         self._mtx_hosts.acquire()
 88         if len(self._game_hosts):
 89             host = self._game_hosts.pop(0)
 90         self._mtx_hosts.release()
 91         return host
 92     
 93 
 94     def test(self):
 95         port = self.getPropertyValue('endpoint.port')
 96         servant = self.getPropertyValue('endpoint.servant')
 97         uri = "%s:tcp -p %s -h %s"%(servant,port,'localhost')
 98         hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
 99         for i in range(100000):
100             print hostprx.getTimestamp()
101             time.sleep(0.5)
102     
103     def killapp(self,host,port,procname):
104         try:
105             servant = self.getPropertyValue('endpoint.servant')
106             uri = "%s:tcp -p %s -h %s"%(servant,port,host)
107             hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
108             print u"终止远程进程: %s-%s"%(host,procname)
109             hostprx.killProcessByName(procname)
110         except:
111             print traceback.print_exc()
112 
113     def launchapp(self,host,port,procname,param=''):
114         try:
115             servant = self.getPropertyValue('endpoint.servant')
116             uri = "%s:tcp -p %s -h %s"%(servant,port,host)
117             hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
118             print u"创建远程进程: %s-%s"%(host,procname)
119             params={'app':'','param':''}
120             params['app'= procname
121             params['param']=param
122             hostprx.launchApp(params)
123         except:
124             print traceback.print_exc()
125     
126     
127     
128     #执行endpoint的更新操作
129     def shutdown(self,host,port):
130         try:
131             servant = self.getPropertyValue('endpoint.servant')
132             uri = "%s:tcp -p %s -h %s"%(servant,port,host)
133             hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
134             print u"执行shutdown: %s"%(host)
135             hostprx.shutdown()
136         except:
137             print traceback.print_exc()
138             
139         
140     #通知远端主机启动游戏 
141     def launchGames(self,host,port,gamepath):
142         try:
143             if True:
144                 servant = self.getPropertyValue('endpoint.servant')
145                 uri = "%s:tcp -p %s -h %s"%(servant,port,host)
146                 hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
147                 #检索主机运行游戏的远端存储目录
148                 print u"启动游戏(%s) of host(%s)"%(gamepath,host)
149                 try:
150                     r = hostprx.launchGame(gamepath)
151                 except:
152                     print "Error: Endpoint Host(%s) Exception Occurred! Skipped"%(host)
153         except:
154             print traceback.print_exc()
155     
156     def terminateGames(self,host,port,gamepath):
157         try:
158             if True:
159                 servant = self.getPropertyValue('endpoint.servant')
160                 uri = "%s:tcp -p %s -h %s"%(servant,port,host)
161                 hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
162                 print "stop game(%s) of host(%s)"%(gamepath,host)
163                 try:
164                     r = hostprx.terminateGame(gamepath)
165                 except:
166                     print "Error: Endpoint Host(%s) Exception Occurred! Skipped"%(host)
167         except:
168             print traceback.print_exc()
169     
170     #执行远程批处理文件
171     def excbat(self,host,port,command):
172         try:
173             hosts = sys.argv[2]
174             logfile = 'excbat.log'
175             servant = self.getPropertyValue('endpoint.servant')
176             uri = "%s:tcp -p %s -h %s"%(servant,port,host)
177             hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
178             if True:
179                 r = hostprx.executeBatchFile(command)
180                 if r.has_key('verbose'): #写入执行日志
181                     print r['verbose']                
182         except:
183             print traceback.print_exc()
184         
185     def update_file(self,hostprx,local,remote,partfile):
186         try:
187             
188             file = os.path.normpath(local+'/'+partfile)
189             fp = open(file,'rb')                        
190             hostprx.syncFileStart("%s%s"%(remote,partfile))
191             while True:
192                 bytes = fp.read(1024*100)
193                 if not bytes:
194                     break
195                 hostprx.syncFileData(bytes)
196             fp.close()
197             hostprx.syncFileEnd()                        
198         except:
199             print traceback.print_exc()
200             #self._app.getErrLogger().error("update file failed:(%s)"%(path))
201             return False
202         return True
203         
204     def update_game(self,hostprx,local,remote,hostname=''):
205         #路径参数都不携带尾端的分隔符
206         try:            
207             #读取忽略文件列表            
208             skipfiles=[]
209             try:
210                 fp = open("%s/skipfiles.txt"%local,'r')
211                 lines = fp.readlines()
212                 for line in lines:
213                     line = line.strip().lower()
214                     if len(line) and line[0]!='#':
215                         line= os.path.normpath(line)
216                         if line[0]!='\\':
217                             line = '\\'+line
218                         skipfiles.append(line) #添加进忽略列表
219                 fp.close()                
220             except:
221                 pass
222             #**************************************
223             #请求远程目录文件清单
224             print u'计算远端主机数据摘要'
225             filelist = hostprx.getFileDescList(remote)
226             
227             #去除目录前缀
228             for n in range(len(filelist)):
229                 idx = filelist[n].filename.index(remote)                        
230                 filelist[n].filename = filelist[n].filename[idx+len(remote):]                
231             #访问游戏列表内的文件存储信息,读取摘要信息到内存
232             
233             digest = os.path.normpath("%s/digest.md5"%local)
234             #print digest
235             fp = open(digest,'r')
236             lines = fp.readlines()
237             fp.close()
238             ##比对远端主机多余的文件,必须先删除
239             removelist=[]
240             #print filelist
241             #print lines
242             for f in filelist:
243                 found = False
244                 for line in lines:
245                     path,size,digest = line.split(DELIMITER)                    
246                     if path == f.filename:
247                         found = True
248                         #print path
249                         break
250                 if found :
251                     continue
252                 #print f.filename
253                 #2009-12-25 忽略删除远端文件
254                 skipmatch = False
255                 for skfile in skipfiles:
256                     if f.filename.find(skfile)!=-1# found
257                         skipmatch = True
258                         break
259                 if not skipmatch:
260                     removelist.append(f.filename)
261                 #----------------------------
262                 #if skipfiles.count(f.filename)!=0:
263                 #    removelist.append(f.filename)
264             #先执行删除远端多余文件
265             #print removelist
266             if len(removelist):
267                 print u"远端共有(%s)个文件将被删除."%(len(removelist))
268             #请求删除远端主机差异文件
269             for file in removelist:
270                 hostprx.deleteFile(remote + file)
271             #
272             #print filelist
273             updatefiles=[]
274             for line in lines:
275                 path,size,digest = line.split(DELIMITER)
276                 #比对文件是否存在和摘要,文件大小不同可即刻判别
277                 needup = True
278                 for f in filelist: #远端文件
279                     if f.filename == path and int(size) == f.size and digest.strip() == f.digest.strip(): #文件同名
280                         needup = False
281                         break
282                 #2009-12-25 忽略更新文件
283                 if needup:
284                     skipmatch = False
285                     for skfile in skipfiles:
286                         if path.find(skfile)!=-1# found
287                             skipmatch = True
288                             break
289                     if skipmatch: #确定是要忽略的文件
290                         needup = False
291                         
292                 #if skipfiles.count(path)!=0:
293                 #    needup = False
294                 
295                 if needup:
296                     updatefiles.append(path)
297             
298             for n in range(len(updatefiles)):
299                 file = updatefiles[n]
300                 print "(%s/%s)%s/%s/%s"%(
301                     n+1,len(updatefiles),str(hostname),local,file)
302                 #file = os.path.normpath(local+"/"+file)                
303                 if not self.update_file(hostprx,local,remote,file):
304                     self._app.getErrLogger().error("update file failed: host(%s),game(%s),file(%s)"%(str(hostname),game.name,file))
305                     return False
306         except:
307             print traceback.print_exc()
308             return False
309         return True
310     
311     def diff_game(self,hostprx,local,remote,hostname=''):
312         #路径参数都不携带尾端的分隔符
313         try:            
314             #读取忽略文件列表            
315             skipfiles=[]
316             try:
317                 fp = open("%s/skipfiles.txt"%local,'r')
318                 lines = fp.readlines()
319                 for line in lines:
320                     line = line.strip().lower()
321                     if len(line) and line[0]!='#':
322                         line= os.path.normpath(line)
323                         if line[0]!='\\':
324                             line = '\\'+line
325                         skipfiles.append(line) #添加进忽略列表
326                 fp.close()                
327             except:
328                 pass
329             #**************************************
330             #请求远程目录文件清单
331             #print u'计算远端主机数据摘要'
332             filelist = hostprx.getFileDescList(remote)
333             
334             #去除目录前缀
335             for n in range(len(filelist)):
336                 idx = filelist[n].filename.index(remote)                        
337                 filelist[n].filename = filelist[n].filename[idx+len(remote):]                
338             
339             digest = os.path.normpath("%s/digest.md5"%local)
340             #print digest
341             fp = open(digest,'r')
342             lines = fp.readlines()
343             fp.close()
344             ##比对远端主机多余的文件,必须先删除
345             removelist=[]
346             #print filelist
347             #print lines
348             for f in filelist:
349                 found = False
350                 for line in lines:
351                     path,size,digest = line.split(DELIMITER)                    
352                     if path == f.filename:
353                         found = True
354                         #print path
355                         break
356                 if found :
357                     continue
358                 #print f.filename
359                 #2009-12-25 忽略删除远端文件
360                 skipmatch = False
361                 for skfile in skipfiles:
362                     if f.filename.find(skfile)!=-1# found
363                         skipmatch = True
364                         break
365                 if not skipmatch:
366                     removelist.append(f.filename)
367 
368             if len(removelist):
369                 pass#print u"远端共有(%s)个文件将被删除."%(len(removelist))
370             for file in removelist:
371                 print "[+]"+file
372             #
373             #print filelist
374             updatefiles=[]
375             for line in lines:
376                 path,size,digest = line.split(DELIMITER)
377                 #比对文件是否存在和摘要,文件大小不同可即刻判别
378                 needup = True
379                 for f in filelist: #远端文件
380                     if f.filename == path and int(size) == f.size and digest.strip() == f.digest.strip(): #文件同名
381                         needup = False
382                         break
383                 #2009-12-25 忽略更新文件
384                 if needup:
385                     skipmatch = False
386                     for skfile in skipfiles:
387                         if path.find(skfile)!=-1# found
388                             skipmatch = True
389                             break
390                     if skipmatch: #确定是要忽略的文件
391                         needup = False
392                         
393                 if needup:
394                     updatefiles.append(path)
395             
396             for n in range(len(updatefiles)):
397                 file = updatefiles[n]
398                 print "[-]"+file
399         except:
400             print traceback.print_exc()
401             return False
402         return True    
403         
404     def update(self,host,port,localpath,remotepath):        
405         if True:
406             try:
407                 
408                 localpath = os.path.normpath(localpath.strip().lower())
409                 if localpath[-1=='\\':
410                     localpath = localpath[:-1]
411                 remotepath = os.path.normpath(remotepath.strip().lower())
412                 if remotepath[-1=='\\':
413                     remotepath = remotepath[:-1]
414                     
415                 servant = self.getPropertyValue('endpoint.servant')
416                 uri = "%s:tcp -p %s -h %s"%(servant,port,host)
417                 hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
418                 self.getLogger().debug(u"开始同步主机:%s"%host)                
419                 if not self.update_game(hostprx,localpath,remotepath,host):
420                     self.getErrLogger().error("update host(%s),game(%s)failed!"%(host,localpath))
421                     return False
422             except:
423                 print traceback.print_exc()
424                 self.getErrLogger().error("update host(%s) failed!"%(host))
425                 return False        
426         return True
427     
428     #本地和远程目录比对
429     #本地必须存在digest.md5,如不存在则先 syncserver2 update 生成
430     def diff(self,host,port,localpath,remotepath):
431         print '='*50
432         print "Diff HOST:%s,PATH:%s"%(host,remotepath)
433         print time.asctime()
434         print '-'*50
435         if True:
436             try:
437                 localpath = os.path.normpath(localpath.strip().lower())
438                 if localpath[-1=='\\':
439                     localpath = localpath[:-1]
440                 remotepath = os.path.normpath(remotepath.strip().lower())
441                 if remotepath[-1=='\\':
442                     remotepath = remotepath[:-1]
443                     
444                 servant = self.getPropertyValue('endpoint.servant')
445                 uri = "%s:tcp -p %s -h %s"%(servant,port,host)
446                 hostprx = ISyncEndpointPrx.uncheckedCast(self.communicator().stringToProxy(uri))
447                 
448                 #self.getLogger().debug(u"开始同步主机:%s"%host)                
449                 
450                 if not self.diff_game(hostprx,localpath,remotepath,host):
451                     self.getErrLogger().error("update host(%s),game(%s)failed!"%(host,localpath))
452                     return False
453             except:
454                 print traceback.print_exc()
455                 self.getErrLogger().error("update host(%s) failed!"%(host))
456                 return False
457         print '='*50
458         return True
459 
460     def usage(self):
461         msg =\
462 '''sync_server(v0.2.1) scott
463 usage:\nsync_server.exe [-d filepath | -h host -p port -k [startgame|update|endgame|excbat] ]
464  -d filepath  - 计算文件摘要,filepath文件目录
465  -h hostname  - 主机ip或者域名
466  -p port      - 主机端口
467  -k startgame dest  - 加载游戏运行,dest - 远程目录
468  -k update src dest - 执行文件同步,src-本地目录;dest-远程目录 
469  -k endgame  dest   - 终止游戏,dest - 远程目录
470  -k excbat batfile - 执行远程文件,batfile带路径的远程主机批处理文件或者命令[blocked]
471  -k shutdown       - 关闭endpoint服务
472  -k killapp procname - 终止指定名称的进程
473  -k launchapp procname - 创建进程
474  -k diff src dest  - 比对本地与远程目录,src-本地目录;dest-远程目录    
475     '''
476         print msg.decode('utf-8')
477         
478     def run(self, args):
479         self.init_games()
480         # init game hosts
481         self.init_hosts()
482         
483         host='localhost'
484         port=5000
485         try:
486             opts, args = getopt.getopt(sys.argv[1:], "h:p:d:k:", ["help""output="])
487         except getopt.GetoptError, err:
488             self.usage()
489             return 0
490         for o, a in opts:
491             if o == "-h":
492                 host = a
493             elif o =='-p':
494                 port = int(a)
495             elif o == '-d'# calc digest                
496                 if not a:                                        
497                     self.usage()                
498                 else:
499                     self.gen_digest(a) #计算摘要
500                 return 0
501             elif o =='-k':
502                 if a=='startgame'#launch game, -k startgame remote_dir
503                     if not host or not port:self.usage();return 0                        
504                     if len(args):
505                         self.launchGames(host,port,args[0]) #args[0] - 文件目录
506                     else:
507                         self.usage()
508                     return 0
509                 elif a=='endgame':
510                     if not host or not port:self.usage();return 0                        
511                     if len(args):
512                         self.terminateGames(host,port,args[0])                    
513                     else:
514                         self.usage()
515                     return 0
516                 elif a == 'update':
517                     if not host or not port:self.usage();return 0                        
518                     if len(args) >=2:
519                         self.update(host,port,args[0],args[1])
520                     else:
521                         self.usage()
522                     return 0
523                 elif a == 'diff':
524                     if not host or not port:self.usage();return 0                        
525                     if len(args) >=2:
526                         self.diff(host,port,args[0],args[1])
527                     else:
528                         self.usage()
529                     return 0
530                 elif a == 'excbat':
531                     if not host or not port:self.usage();return 0                        
532                     if len(args):
533                         self.excbat(host,port,args[0])                        
534                     else:
535                         self.usage()
536                     return 0
537                 elif a == 'shutdown':
538                     if not host or not port:self.usage();return 0                        
539                     self.shutdown(host,port)
540                     return 0
541                 elif a == 'killapp':
542                     if not host or not port:self.usage();return 0                        
543                     if len(args):
544                         self.killapp(host,port,args[0])                        
545                     else:
546                         self.usage()
547                     return 0
548                 elif a == 'launchapp':                    
549                     if not host or not port:self.usage();return 0                    
550                     if len(args):
551                         param=''
552                         
553                         if len(args) >1:
554                             param = args[1]
555                         self.launchapp(host,port,args[0],param)                        
556                     else:
557                         self.usage()
558                     return 0
559                 
560             else:
561                 self.usage()
562                 return 0
563         self.usage()
564         return 0
565 
566     def getPropertyValue(self,propName,default=''):
567         return self.communicator().getProperties().getPropertyWithDefault(propName,default)
568     
569     def getPropertyIntValue(self,propName,default=0):
570         try:
571             default = int(default)
572         except:
573             default = 0 
574         return self.communicator().getProperties().getPropertyAsIntWithDefault(propName,default)
575     
576 #在游戏目录下计算并存放摘要信息,一个游戏目录支持在一个摘要文件 
577     def gen_digest(self,filepath):
578         NOCARE_FILES=['digest.md5','skipfiles.txt']
579         #gamelist = self.getGameList()
580         #for game in gamelist:
581         if True:
582             try:
583                 filepath = filepath.strip().lower()
584                 filepath = os.path.normpath(filepath)
585                 if filepath[-1]=='\\'#rid of terminated character
586                     filepath=filepath[:-1]                
587                 file = "%s/digest.md5"%filepath
588                 
589                 fp = open(file,'w')
590                 self.getLogger().debug(u"扫描文件目录(%s)"%(filepath))                
591                 #不能记录game.path前缀
592                 for root, dirs, files in os.walk(filepath, topdown=False):
593                     for name in files:
594                         if NOCARE_FILES.count(name)!=0:
595                             continue
596                         file = os.path.join(root, name).lower().strip()
597                         size = os.stat(file).st_size
598                         digest = codec.calcFileMd5Digest(file)
599                         if size == 0:
600                             #print file,size,digest
601                             #return
602                             pass
603                         idx = file.index(filepath)
604                         file = file[idx+len(filepath):] #保留\
605                         fp.write(file+DELIMITER+str(size)+DELIMITER+digest+"\n")
606                 fp.close()
607             except:
608                 print traceback.print_exc()
609         pass    
610 
611 ##############################################################
612     
613 ##############################################################
614 if __name__=='__main__':
615     
616     server = syncApp()
617     sys.exit(server.main(sys.argv, "../etc/server.conf"))
618     
619     
620         
621     



posted on 2010-09-30 00:34 放屁阿狗 阅读(2125) 评论(0)  编辑 收藏 引用 所属分类: perl/python/php/lua/tcl

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理