Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5119927
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Python/Ruby

2012-03-12 11:16:35

    原创文章,转载请注明出处
    在之前的准备工作中,我们已经,并且经过了,得到的结论是python可以满足我们的需求,那么接下来,我们要解决的是身为webgame服务端必须的几个功能模块:

    一、记录和维护所有客户机的状态
    更新:按照同学的建议,这里直接用self.transport.sessionno即可,查twisted文档的时候我忽略了这个东西。因此无需按照我下面的方法来手动维护,好吧,我造了一次轮子……    

    为了实现这个功能,我们先回过头来分析下之前的服务端代码:
    1、每个客户端连接会有一个gameSocket对象被创建,然后触发connectionMade事件。
    2、客户端数据到达的时候触发dataReceived事件
    3、连接断开的时候触发connectionLost事件,然后对象被析构

    根据通常的处理思路,我们需要为每个客户端建立一个编号,即传说中的sockid,然后维护一个client和sockid之间的双向字典,以便我们能够简单的互相反查。我决定维护2份数据,以空间换时间,新建一个sockMana类来实现该功能:

点击(此处)折叠或打开

  1. # sockmana.py
  2. class SockMana:
  3.     def __init__ (self):
  4.         self.sockNum = 0 #记录当前的在线总数
  5.         self.sockIndex = 1 #累加sockid
  6.         self.client2id = {} #保存client->sockid字典
  7.         self.id2client = {} #保存sockid->client字典

  8.     def addClient(self,client):
  9.         #增加一个客户端
  10.         print '** add client **'
  11.         self.sockNum = self.sockNum + 1
  12.         self.client2id[client] = self.sockIndex
  13.         self.id2client[self.sockIndex] = client
  14.         self.sockIndex = self.sockIndex + 1

  15.         print self.sockNum
  16.         print self.client2id
  17.         print self.id2client
  18.     
  19.     def delClient(self,client):
  20.         #删除一个客户端
  21.         print '** del client **'
  22.         if client in self.client2id:
  23.             self.sockNum = self.sockNum - 1
  24.             _sockid = self.client2id[client]
  25.             del self.client2id[client]
  26.             del self.id2client[_sockid]

  27.             print self.client2id
  28.             print self.id2client
  29.     
  30.     def getSockid(self,client):
  31.         #通过client获取sockid
  32.         if client in self.client2id:
  33.             return self.client2id[client]
  34.         else:
  35.             return None
  36.         
  37.     def getClient(self,sockid):
  38.         #通过sockid获取client
  39.         if sockid in self.id2client:
  40.             return self.id2client[sockid]
  41.         else:
  42.             return None

  43. #初始化连接管理器
  44. sockMana = SockMana()
 接下来在我们的socket服务端代码中import它,并增加调用事件,然后略修改dataReceived事件,当收到客户端数据的时候,我们向客户端返回它的sockid,完整的服务端代码调整为:


点击(此处)折叠或打开

  1. import os
  2. if os.name!='nt':
  3.     from twisted.internet import epollreactor
  4.     epollreactor.install()
  5. else:
  6.     from twisted.internet import iocpreactor
  7.     iocpreactor.install()
  8. from twisted.internet.protocol import Factory,Protocol
  9. from twisted.internet import reactor
  10. from sockmana import sockMana

  11. class gameSocket(Protocol):
  12.     #有新用户连接至服务器
  13.     def connectionMade(self):
  14.         sockMana.addClient(self)
  15.         print 'New Client'
  16.     
  17.     #客户端断开连接
  18.     def connectionLost(self,reason):
  19.         sockMana.delClient(self)
  20.         print 'Lost Client'
  21.     
  22.     #收到客户端发送数据
  23.     def dataReceived(self, data):
  24.         print 'Get data:' + str(data)
  25.         #向该客户端发送数据
  26.         self.transport.write('your sockid is:'+ str(sockMana.getSockid(self)))
  27.     
  28. if __name__=='__main__':
  29.     f = Factory()
  30.     f.protocol = gameSocket
  31.     reactor.listenTCP(5200,f)
  32.     print 'server started...'
  33.     reactor.run()
然后我们依然用telnet,来建立2个连接试试


可以看到,每增加一个客户端,我们的sockMana类中就会分别增加2个 key->val的键值对,通过sockMana.getSockid方法即可获取客户端的sockid,这样我们就为每个客户端建立了一个唯一且可用于传递和储存的数值编号,在以后的逻辑处理中,这将作为客户端的唯一标识。

    好了,我们断开其中一个客户端,看看我们的sockMana工作正常否?
 
 Yes!和预料中的一样,一切工作正常。我们又向前迈进了小小的一步,下面,我们得研究研究服务端如何和客户端之间高效的传输数据了。
补充:
貌似不用来手动的给客户端去分配ID,直接去transport的sessionno 就可用。
class socketProtocol(protocol.Protocol):
    '''
    socket通信处理协议
    buff 缓冲
    '''
    buff = ""
    def connectionMade(self):
        '''
        连接建立处理
        '''
        log.msg('Client %d login in.[%s,%d]'\
%(self.transport.sessionno,self.transport.client[0],self.transport.client[1]))
 
@jinmin_lan 确实,应该直接用self.transport.sessionno即可,被我弄复杂了。
阅读(1119) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~