美文网首页
大作业 - 4 服务器实现

大作业 - 4 服务器实现

作者: lmzqwer2 | 来源:发表于2016-03-30 21:20 被阅读128次

    前面又是分析又是设计的,而到了这一步,所有的东西将会落实到代码上,成为一个真正能用的服务器。

    KeepList组件

    class Connection(object):
        # 以list的形式存储客户端
        # KeepList保证在remove的时候,不改变其余所有项目的位置
        # 而是选择在原处留下删除印记,客户端的句柄会优先放置在有印记的位置
        client = KeepList()
    

    上回说到,Connection实例的存储方式是一个有特殊功能的list。自然python没有自带这种奇怪功能的库,所以还需要我们自己实现。

    为了实现删除不改变其余项目的位置的功能,可以直接将被删位置赋值为None。但是由此所带来的是list大小无限增大的隐患,即每次新的节点均增加在list末尾,并使list长度增加,而删除却不会使list减少。所以,为了解决这个隐患,每次添加的时候均需要首先考虑原本被删除的位置。而每次插入的时候都遍历一遍list也不现实,需要更好的算法。

    为了实现这样的功能,我选择使用类似于链表的结构实现快速删除以及快速插入功能。具体来说,是使用一个与数据list等长的另一个下标list与其中每一项一一对应。下标list中每个位置的可能取值为-1~len(list)-1,即是数据list中每一项的下标再加一个指向空的-1。

    下标list所起的作用是通过下标的方式,将所有被删除的位置串联起来。而当某项下标list中所对应的项为-1,表示该位置指向空。而如果有值,则是说明当前项已经被删除,同时,下一个被删除的项是list所指向的项。由此,所有被删除的节点会被该list串成一条链表,每次使用的时候只需要访问链表头即可。

    每次插入节点时,检测链表头是否指向节点,而后选择添加在末尾还是进行填空。而每次删除的时候,直接更新链表头,即在链表头前插入一个新的节点,并更新表头。

    这样做会导致最先插入的新节点在最近删除的位置,而不是与删除顺序一致。不过由于该项目所需的只是一个固定下标以示区分而并不关心下标的大小,所以该方法可行。

    消息传递

    整个系统选择使用json格式进行消息传递,虽然这有可能导致传输数据的冗余,但是就当前项目规模而言,所需要的是易用性以及良好的可扩展性。而这都是json所其所具有的特性。

    消息的传递是本服务器的重中之重,虽然涉及到的算法不多,但是对于权限检测等方面还是需要小心。

    网页端

    网页端的逻辑使用js编写。在整个系统中,网页端作为用户接触到的一层,其主要身份是一个请求的发起者以及结果的接收者。

    首先,作为发起者,需要监测的是浏览器中的按键消息,而后通过与浏览器建立的WebSocket连接发送按键消息。浏览器中自带有JSON模块,能够很方便得收发json。

    同时,由于socket建立连接后,并没有如同http请求一样的一发一收的功能,所以,浏览器这一端的表现主要通过服务器端进行控制。换言之,就是浏览器中按下的按键并不由浏览器直接进行识别,而是发送至服务器之后,由服务器返回消息进行处理。

    使用这种思路,可以避免服务器与网页端的逻辑对比,不过对于用户来说,可能会感受到较高的延迟。

    服务器

    服务器端的逻辑主要体现在消息转发以及用户身份验证上。

    本项目对于用户身份的验证,并不需要太强,只需要能够以示区分即可。所以,并不需要数据库进行用户数据存储,用户所面对的是一个不需要密码的登录界面,用以输入用户名。当然,可以考虑在后期加入与课程中心服务器进行密码验证的过程。

    服务器在接收到登录请求之后,会将用户名与另外一个随机的值联合起来算出md5作为该用户的识别码,并将用户名与识别码一起存在客户端的cookie中。用户名作为显示给用户看的弱识别码,而识别码以用户名加随机数求md5进行生成,碰撞概率较小,用于服务器端用户身份的直接识别。

    当服务器收到用户的WebSocket请求的同时,会记录下其身份识别码,并通过检测页面访问的位置按照格式将句柄加入对应的树莓派集合中。而当用户发送相关按键消息的同时,服务器会判断其是否为操控者而决定是否转发该请求至树莓派。

    而服务器在接收到树莓派消息的同时,默认将其广播至所有连入的web端。

    树莓派端

    send(人多)send(病少)send(财富)
    recv(人多病)recv(少财富)

    树莓派端通过socket与服务器进行连接。由于服务器端已经有 Tornado框架的封装,使用起来较为容易。而未经封装的树莓派端socket协议很容易由于各种原因导致缓存中存在不止一次的请求,而将所有的请求一次性读入之后需要逐一处理。所以每次发送与接受的时候,需要有一个分隔符将两次请求分割开来。

    而作为信息传输格式的json就有这种功能,因为每一个合法的json结尾都是"}"。而通过识别"}"即可将每个请求分割开来进行执行。

    虽然json本身可能会含有带}的字符串,但是就目前项目的需求而言,暴力使用}分割即可。

    文件传输

    由于WebSocket发送二进制的能力较弱,所以换用http请求发送文件至服务器。而在发送文件的同时,浏览器会验证cookie中所携带的识别码是操控者的身份,据此判断是否接收文件。

    由于.bit文件并不是特别大,所以,接收文件后,文件以二进制方式存在于内存中即可。

    树莓派端的文件获取方式在服务器v0.1以及v0.2版本中比较不一致。

    在服务器0.1版本中,使用base64编码方式将二进制变为字符串,而后直接使用socket进行发送。树莓派接收完成后使用base64解码即得目标文件。

    而在服务器0.2版本中,服务器会向树莓派推送一条消息,而树莓派根据这条消息的内容,通过HTTP协议下载服务器上的文件。

    小结

    就此,浏览器端与树莓派的交流已经打通,文件的传输也进行了相关支持,服务器端的最主要的部分已经结束。

    但这个项目还需要完善。当前的前端页面仅仅只是能用而已,后续需要进行增强,如支持断线重连、支持rtmp直播播放、屏幕按键显示支持等。而树莓派端也需要与实验板进行通信后才能真正回馈有价值的消息。

    服务器的完成只是一个开始!

    参考资料

    相关文章

      网友评论

          本文标题:大作业 - 4 服务器实现

          本文链接:https://www.haomeiwen.com/subject/njwklttx.html