好,经过上一篇不权威的讲解,大家已经能轻易地让客户端和服务端连接起来了。

但是,仅仅是连接了,可它们俩不说话不交流,那游戏就玩不起来了,玩不起来那我就赚不到钱..啊不是,玩不起来那玩家就不能开心了,钱是…啊不!玩家是最重要的嘛~不能让玩家不开心(小若:好好好,看出来了,钱是最重要的是吧)

好~!这次木头就和大家一起见证客户端和服务端的第一次交谈吧~!

声明:

本教程基于FireFly1.2.2版本、Python2.7版本。

本教程面向Python和FireFly初学者中的初学者(比如我)

本教程由笨木头花心贡献,花心?不,是用心~!

转载请注明原文地址:http://www.benmutou.com/blog/archives/727

1. Pythone struct模块

Struct模块主要是用来对数据进行打包和解包的,和LiberateFactory不一样,LiberateFactory已经说了,是协议工厂,当然就主要是对协议进行封装和解析。而struct是对更底层的数据操作,是把数据打包成二进制的形式,然后在网络中传输。解包也一样,把二进制形式的数据解包成Pythone需要或者说比较好识别的格式。

反正,总之,struct模块是对数据进行打包和解包的,解释完毕~

2. 可以发送请求的客户端(client.py)

我们要修改客户端,以便它可以发送数据给服务端。

#coding:utf8'''
Created on 2013-10-8@author: 笨木头_钟迪龙 www.benmutou.com
'''from socket import AF_INET, SOCK_STREAM, socket
import struct
def sendData(sendstr, commandId):
HEAD_0 = chr(0) # 协议头0
HEAD_1 = chr(0) # 协议头1
HEAD_2 = chr(0) # 协议头2
HEAD_3 = chr(0) # 协议头3
ProtoVersion = chr(0) # 协议头版本号
ServerVersion = 0 # 服务器版本号
sendstr = sendstrdata = struct.pack('!sssss3I', HEAD_0, HEAD_1, HEAD_2, HEAD_3,\
ProtoVersion, ServerVersion, len(sendstr) + 4, commandId)senddata = data + sendstr
return senddataif __name__ == '__main__':
HOST = "localhost" # 服务端地址
PORT = 1000 # 服务端端口
ADDR = (HOST, PORT)client = socket(AF_INET, SOCK_STREAM) # 创建socket,TCP
client.connect(ADDR) # 连接服务器
client.sendall(sendData('hello server', 1))# 发送数据给服务器
while True:
pass

觉得复杂吗?其实就多了一个sendData函数而已。(小若:但是它很复杂!)

2.1 协议头部信息

我们先来解释一下协议头、协议头版本号、服务器版本号。我也没有深入了解,但就这么看,我唯一能想到的就是:这些东西是用来检测客户端和服务端是否同步的。

经过我“深入”FireFly源码之后,发现了确实有这么一个用途,当服务端的协议工厂接收到数据时,会先判断这些协议头和版本号是否正确,不正确的话,是不会往下继续执行的。

由于这是入门教程,就不一层层地贴这些代码了,也不继续深入了,因为它不是本文的重点。

重点是struct的pack函数,大家可以看看这篇文章:

http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html

只看第1、2点就暂时够用了。

于是,上面代码里的pack函数就是把4个协议头、协议头版本号、服务器版本号、发送的数据长度、命令码打包。

这样打包后的数据作为一个数据的头部信息,顾名思义,头部信息就是记录一次发送数据的主要信息,比如长度、版本、命令码。(小若:废话!上面都说了把这些东西打包了)

然后我们看看这句代码:senddata = data + sendstr。

为什么发送的数据字符串不需要参与打包呢?我也很白痴地试了一下把数据字符串也一起参与打包,结果是一样的。

于是,据我所知,字符串可以直接传输(字节流),不需要再进行什么打包了。

2.2 发送数据

客户端要发送数据给服务端很简单:client.sendall(sendData(‘hello server’, 1))

这句代码的意思是,发送字符串‘hello server’给服务端,命令码是1。

结合之前说的,命令码1会参与到数据头部信息一起打包,而字符串’hello server’是直接和打包后的数据连接的,不需要参与打包。

2.3 为什么数据长度要+4?

不知道大家会不会有个疑问,就是打包的时候这个参数:len(sendstr) + 4

为什么长度要+4,木头我是弄不明白了,我查看了源码,在解析头部信息的时候,获取数据长度值时,又减去了4。这看起来有点多此一举,据我目前的研究,还没法知道原因,希望高手支招。

3. 可以接收请求的服务端(server.py)

服务端的改动也很小,看代码:

#coding:utf8
'''
Created on 2013-10-8@author: 笨木头_钟迪龙 www.benmutou.com
'''import os
import sysfrom firefly.netconnect.protoc import LiberateFactory
from firefly.utils import services
from twisted.internet import reactor
from twisted.python import logif os.name!='nt':#对系统的类型的判断,如果不是NT系统的话使用epoll
from twisted.internet import epollreactor
epollreactor.install()def command_1(_conn, data):
print '我跟你说,别以为你的命令码正确了,我只是不想让你错误而已~!'
print dataif __name__ == '__main__':
# 有了它,就能看到日志的输出
log.startLogging(sys.stdout)# 服务,我个人理解为对客户端数据的逻辑处理service = services.CommandService("testService")# 添加一个命令码处理service.mapTarget(command_1)# 处理数据封装、协议头封装、分包、粘包处理的类factory = LiberateFactory();# 关于twisted的知识,暂时忽略吧,我也还没研究,是一个Python的网络框架reactor = reactor#添加服务通道factory.addServiceChannel(service)# 开始监听端口reactor.listenTCP(1000, factory);reactor.run()

最明显的是多了一个command_1函数,这个函数就是用来处理命令码为1的请求的,怎么处理?大家还记得service吧?Service就是用来处理这些请求逻辑的。

看看下面这两句新增的代码:

# 服务,我个人理解为对客户端数据的逻辑处理

service = services.CommandService(“testService”)

# 添加一个命令码处理

service.mapTarget(command_1)

首先,我们把Service改为了CommandService,这就说明了两个问题。第一,CommandService是专门用来处理命令码这种类型请求的服务;第二,Service是可以自定义的,这样就可以按我们的需要进行自定义处理,而CommandService就是其中一个自定义的服务。

然后,我们只要用service的mapTarget函数就能给service新增一个处理逻辑,在这里我们就说是添加了一个命令码的处理。

这里把函数命名为command_1是有讲究的,mapTarget会把下划线’_’后面的数值作为key值,函数对象作为value值,保存起来。当客户端发来请求时,就会根据命令码找到对应的函数对象。

怎么样?服务端就是这么处理的命令码的,很简单吧,具体的代码我就不贴了,因为本文是点到即止的入门教程。

4. 试验一下

大家现在就运行服务端,然后运行客户端,如果能看到类似以下的日志,那么就恭喜你了,你成功了:

2013-10-08 22:43:59+0800 [-] Log opened.

2013-10-08 22:43:59+0800 [-] LiberateFactory starting on 1000

2013-10-08 22:43:59+0800 [-] Starting factory <firefly.netconnect.protoc.LiberateFactory instance at 0x0000000002FEA588>

2013-10-08 22:44:02+0800 [firefly.netconnect.protoc.LiberateFactory] Client 0 login in.[127.0.0.1,20708]

2013-10-08 22:44:02+0800 [LiberateProtocol,0,127.0.0.1] call method command_1 on service[single]

2013-10-08 22:44:02+0800 [LiberateProtocol,0,127.0.0.1] 我跟你说,别以为你的命令码正确了,我只是不想让你错误而已~!

2013-10-08 22:44:02+0800 [LiberateProtocol,0,127.0.0.1] hello server

5. 再来串一遍

如果你是一个正常的、正宗的、不是假冒的初学者,那么,你现在一定是这样一种状态:代码运行成功了,结果也正确了,好像知道了是怎么回事了,但是又没办法把整个流程顺畅地回忆起来。

那就对了,我们把客户端发送数据到服务端接收并处理数据的流程再过一遍,这样就清楚了:

1) 客户端发送数据: client.sendall(sendData(‘hello server’, 1))

2) 发送数据之前先把4个协议头、协议头版本号、服务器版本号、数据长度+4、命令码打包,然后再加上数据字符串’hello server’,整个要发送的数据就准备好了,然后发送,至于怎么发送的,我们不管,这是socket的事情。

3) 经过某些未知的步骤,我们的数据来到了LiberateFactory协议工厂,它负责解析数据,把命令码和数据内容拆分好,然后传给CommandService对象

4) CommandService根据命令码找到对应的函数,然后执行函数

5) 完成。

当然,也许中间有某些步骤被我不经意间忽略了(也许是故意的,也许是能力问题),不过,作为初步了解客户端和服务端的通信过程,也已经足够了。

再次声明,我也是刚接触FireFly和Python,请带着批判的眼光看待本文,本文为木头个人学习记录,仅供参考。

[笨木头FireFly 02]入门篇_客户端发送请求,服务器处理请求相关推荐

  1. [笨木头FireFly 02]入门篇2_客户端发送请求,服务器处理请求

    原地址:http://www.9miao.com/question-15-53940.html 好,经过上一篇不权威的讲解,大家已经能轻易地让客户端和服务端连接起来了. 但是,仅仅是连接了,可它们俩不 ...

  2. 【笨木头Unity】入门之旅010(完结):Demo之四处找死(五)_UI

    UI是游戏里必不可少的元素,在Unity里添加UI是比较轻松的事情,但要玩好它,可就不那么轻松了. 没关系,先入门. 笨木头花心贡献,啥?花心?不,是用心. 转载请注明,原文地址:http://www ...

  3. python 服务端渲染_客户端渲染和服务器渲染的区别

    我们都知道,网页上的很多内容之所以能那么丰富,是因为大量的css.js去渲染出这个页面.那么他们是如何渲染的呢?那么就要说到我们本文的两种渲染方式了,即客户端渲染和服务端渲染. 正文 本文将分别讲述两 ...

  4. [笨木头FireFly 03]完整的服务端和客户端通信

    #PS: 其实这篇文件是2013.10.12写完的,一直没发布,因为从那天起,我又跑回去折腾客户端的东西了(打算用Cocos2d-x3.0做下一个游戏),以及我的老游戏的维护和更新.总之各种借口(小若 ...

  5. 【笨木头Unity】入门之旅006:Demo之四处找死(一)_场景和主角

    终于把一些基本的东西介绍完了,我不想再介绍无聊的菜单和快捷键了,这些东西大家自己在折腾的过程中慢慢熟悉就好. 有什么不懂的就问度娘,不喜欢度娘的,可以找谷歌. 这次,我们来开始一个很简单的Demo,我 ...

  6. 【笨木头Unity】入门之旅007:Demo之四处找死(二)_主角移动和旋转

    上一篇我们仅仅是创建了场景和主角,暂时不具备任何玩法. 这次,我们来看看怎么让主角移动起来. 笨木头花心贡献,啥?花心?不,是用心. 转载请注明,原文地址:http://www.benmutou.co ...

  7. 【笨木头Unity】入门之旅009:Demo之四处找死(四)_在代码里操作物体

    有没有发现越往后写,旁白出现的次数越少? 是的,最近公司出了点小问题,思绪就变得沉重了一些,思绪一沉重,我的精神分裂就很难发作. 不唠叨了,这次我们来试试在代码里操作物体吧,很简单很简单的. 笨木头花 ...

  8. 【笨木头Unity】入门之旅008:Demo之四处找死(三)_触发器

    好了,游戏开始进入奇怪的阶段了,接下来我们要在场景里放上地雷,终结这个帅气的BugPlayer吧. 笨木头花心贡献,啥?花心?不,是用心. 转载请注明,原文地址:http://www.benmutou ...

  9. 【笨木头Unity】入门之旅005:正常人都要掌握的操作

    各位,对不起,我一直都很想快点进入代码的教程,但是不知道为什么,老是在编辑器这边徘徊. 这不,本篇又要介绍编辑器了,唉.(小若:好可怜-个屁吖,还不是你自己要介绍的!) 笨木头花心贡献,啥?花心?不, ...

最新文章

  1. el图片滚动_element的el-table中记录滚动条位置的示例代码
  2. iOS应用开发入门(2)——添加一个按钮
  3. 公众号滑动图代码_脱离模板!教你自己动手制作公众号封面图
  4. mysql分区失败_MYSQL表分区操作错误1503解决方案
  5. python中xlsxwriter_python xlsxwriter使用方法汇总
  6. s3k3 破旧不堪的拐杖被扔出去几米远
  7. 算法高级(41)-推荐算法实现
  8. linux结构体大小端,【转】位结构体+大小端模式
  9. Python模拟汉诺塔问题移动盘子的过程
  10. Internet控制报文协议ICMP
  11. 遍历出List<Map>的Key / Value
  12. 线性代数学习笔记——第十九讲——克拉默法则
  13. c语言 老鼠乘法,c语言-老鼠走迷宫逐步理解
  14. 2023最新素材解析网站源码搭建和原理,附带PHP小例子。
  15. 异常问题-NXP的Flash锁死后无法烧录
  16. 理解什么是接口测试?怎样做接口测试?
  17. 全球与中国DIN导轨式信号调理器市场现状及未来发展趋势
  18. php usc2,CSDN 免积分下载原理
  19. 围绕“场景+人”,戴尔商用终端做了一篇大文章
  20. Python读取Word文档中的Excel嵌入文件

热门文章

  1. [转] Carmack 谈 d3d 与 ogl,定位专业应用的OpenGL,专注娱乐应用的DirectX,未来:OpenGL、DirectX并行发展
  2. 百度网盘和百度云一样吗?
  3. Linux 平台下基于Qt 的电子地图的绘制
  4. 电子式射频开关(电子RF开关,电子开关,RF Switch)
  5. amd服务器6300系列,AMD新款Opteron 6300服务器CPU终极评测
  6. 用vim和Markdown, 将MySQL导出的备份转换为HTML格式的数据字典
  7. 超好看的3D烟花代码(html+css+js)带音乐
  8. java相同字符组合归类_对相同字母组合的单词进行归类
  9. QT命令行编译时出现'mingw32-make'不是内部或外部命令,也不是可运行的程序或批处理文件
  10. 数字人民币生态体系进一步完善 试点场景加速拓展