zoukankan      html  css  js  c++  java
  • 转:: 刺鸟:用python来开发webgame服务端(3)

    来源:http://ciniao.me/article.php?id=11

    ---------------

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

        一、记录和维护所有客户机的状态
        更新:按照jinmin_lan同学的建议,这里直接用self.transport.sessionno即可,查twisted文档的时候我忽略了这个东西。因此无需按照我下面的方法来手动维护,好吧,我造了一次轮子……    
        为了实现这个功能,我们先回过头来分析下之前的服务端代码:
        1、每个客户端连接会有一个gameSocket对象被创建,然后触发connectionMade事件。
        2、客户端数据到达的时候触发dataReceived事件
        3、连接断开的时候触发connectionLost事件,然后对象被析构


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

    # sockmana.py
    class SockMana:
        def __init__ (self):
            self.sockNum = 0 #记录当前的在线总数
            self.sockIndex = 1 #累加sockid
            self.client2id = {} #保存client->sockid字典
            self.id2client = {} #保存sockid->client字典
    
        def addClient(self,client):
            #增加一个客户端
            print '** add client **'
            self.sockNum = self.sockNum + 1
            self.client2id[client] = self.sockIndex
            self.id2client[self.sockIndex] = client
            self.sockIndex = self.sockIndex + 1
    
            print self.sockNum
            print self.client2id
            print self.id2client
        
        def delClient(self,client):
            #删除一个客户端
            print '** del client **'
            if client in self.client2id:
                self.sockNum = self.sockNum - 1
                _sockid = self.client2id[client]
                del self.client2id[client]
                del self.id2client[_sockid]
    
                print self.client2id
                print self.id2client
        
        def getSockid(self,client):
            #通过client获取sockid
            if client in self.client2id:
                return self.client2id[client]
            else:
                return None
            
        def getClient(self,sockid):
            #通过sockid获取client
            if sockid in self.id2client:
                return self.id2client[sockid]
            else:
                return None    
    
    #初始化连接管理器
    sockMana = SockMana()

        接下来在我们的socket服务端代码中import它,并增加调用事件,然后略修改dataReceived事件,当收到客户端数据的时候,我们向客户端返回它的sockid,完整的服务端代码调整为:

    import os
    if os.name!='nt':
        from twisted.internet import epollreactor
        epollreactor.install()    
    else:
        from twisted.internet import iocpreactor
        iocpreactor.install()
    from twisted.internet.protocol import Factory,Protocol
    from twisted.internet import reactor
    from sockmana import sockMana
    
    class gameSocket(Protocol):
        #有新用户连接至服务器
        def connectionMade(self):
            sockMana.addClient(self)
            print 'New Client'
        
        #客户端断开连接
        def connectionLost(self,reason):
            sockMana.delClient(self)
            print 'Lost Client'
        
        #收到客户端发送数据
        def dataReceived(self, data):
            print 'Get data:' + str(data)
            #向该客户端发送数据
            self.transport.write('your sockid is:'+ str(sockMana.getSockid(self)))
        
    if __name__=='__main__':
        f = Factory()
        f.protocol = gameSocket
        reactor.listenTCP(5200,f)
        print 'server started...'
        reactor.run()

        然后我们依然用telnet,来建立2个连接试试。

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

        好了,我们断开其中一个客户端,看看我们的sockMana工作正常否?

         Yes!和预料中的一样,一切工作正常。我们又向前迈进了小小的一步,下面,我们得研究研究服务端如何和客户端之间高效的传输数据了。

    #本文由刺鸟原创,欢迎转载,但请保留出处,也欢迎对本文感兴趣的同学多多交流。#

    -----

  • 相关阅读:
    SpringMvc@RequestParam 来映射请求参数
    SpringMvc中@PathVariable注解简单的用法
    SpringMvc的学习之路
    平常的操作函数以及回调
    关于弹窗 取消 确定清空按钮的事件
    判断主表里子表不能添加相同的字段
    选择company回显appname
    树形菜单数据源
    .NET为什么要使用异步(async)编程?⭐⭐⭐⭐⭐
    通过HttpClient的方式去Curd数据⭐⭐⭐⭐
  • 原文地址:https://www.cnblogs.com/ezhong/p/3385769.html
Copyright © 2011-2022 走看看