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

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

刺鸟原创文章,转载请注明出处
    前面的工作都已准备就绪,现在我们得来看看服务端怎么和客户端之间进行通信了,Python和FLASH之间的通信,我整理为以下3种:

1、用现成的协议及类库处理,比如:pyamf
    2、自己封包进行二进制数据流通信
    3、用JSON字符串通信

一、JSON和二进制数据流的优缺比较
    pyamf有比较现成的文档,因此,这里我主要研究研究后两种。我们先简单分析下JSON和数据流各自的优缺点:
    JSON:
    优点:数据结构灵活,无需先制定复杂的协议;跨语言之间基本都有完整的解决方案。
    缺点:传送的数据因为要增加json的特征符(',"",:,{等),导致数据量较大;明文传输,无安全性可言。
    二进制数据流:
    优点:数据量小,无协议文档的话,较难破解内容。
    缺点:数据不灵活,需要先制定足够完善的协议文档。

权衡利弊,在当前项目中,采用二进制数据流是更为合适的方案。

二、拆包和粘包
    我们下面来了解下python对于数据流通信这块的功能。根据TCP/IP通信的特点,不管是采用JSON字符串,还是二进制数据流,都必须面临的一个问题是:数据的拆包和粘包,具体的问题表现如下:
    采用如下代码,向socket服务器发送5000长度的数据,可以看到,在数据大于4000左右的时候被拆包,触发了服务端的2次dataReceived事件。

conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect(("127.0.0.1", 5200))
conn.send('abcdefghij'*500)

服务端接收情况:

也即是说,在这里我们得粘包,保证数据完整后,才执行对应的逻辑。还有另外一种情况:客户端两次短暂的间隔时间内向服务端发送数据流时,TCP协议会将这2次数据合并为一次后,发送给服务端,如果遇到这样的情况,就需要我们对数据进行拆包处理。

三、常见的数据格式
    传输的数据中,常见的包括以下类型:字符串(长度可变),字节(1位),长整数(4位),无符号整形(4位),短整形(2位)。以上数据中,字符串是长度未定的,因此我们得使用一个短整型在字符串前,以便程序能知道后面的string占了几位。
    另外,为了计算封包的完整性,我们需要在封包首尾各指定一特殊的标示位。为了快速的读取数据,我们需要在封包头记录其长度。综上,我们制定了如下封包格式:

0x11 + 封包长度 + 协议号 + 数据 + 0x22

当中协议号int型(如:3290),如果数据是string,则保存为 short(str长度) + string(str内容)

四、python的二进制处理库
    有了封包格式,我们再来看下python中如何编码实现封包,这时,我们需要用到struct库,struct库主要有以下3个方法:

struct.pack(fmt,v1,v2,.....)

将v1,v2...等参数的值进行pack处理,pack的格式由fmt指定。被pack参数必须严格符合fmt。最后返回一个包装后的字符串。

struct.unpack(fmt,string)

顾名思义,解包,返回一个由解包数据(string)按照fmt格式解包后的元组(即使仅有一个数据也会被解包成远祖)。

struct.calcsize(fmt)

用来计算fmt格式所描述的结构的大小

其中,fmt的格式所代表的含义和更多对struct的介绍,请浏览官方文档

五、我们的pack
    接下来,需要写一个方法,来按照我们的封包格式,对数据进行pack处理。

#coding:utf-8
#基于python2.6
'''
按照我的习惯,重写struct的格式化符为:
s=字符串
b=字节
i=长整数
u=无符号整形
n=短整形
'''
datafmt = {
'':'ssbi',
#指定1001协议的数据格式,如果按如上指定,则表示该封包由
#字符串 + 字符串 + 字节 + 长整型
#构成
}
import struct
#对数据进行pack数据 comid(string)=协议号 data(list)=数据内容
def pack(comid,data):
global datafmt
if comid not in datafmt:
print comid,'协议fmt格式读取错误' fmtStr = datafmt[comid]
fmtStrRes = []
idx = 0
fixString ={} for k in fmtStr:
if k=='n':
fmtStrRes.append('h')
elif k=='b':
fmtStrRes.append('b')
elif k=='u':
fmtStrRes.append('I')
elif k=='i':
fmtStrRes.append('i')
elif k=='s':
_strLength = len(data[idx])
fixString[idx] = _strLength #记录str的长度
fmtStrRes.append('h'+ str(_strLength) +'s')
idx = idx + 1 fmt = '<'+''.join(fmtStrRes) #将字符串的长度值插入到data中
if len(fixString)>0:
idx = 0
for k,v in fixString.items():
data.insert(k+idx,v)
idx = idx + 1 print 'data=',data
print 'fmt=',fmt res = struct.pack(fmt,*data)
print 'pack=',res pack('',['abc','中文',3,7654])

运行看看:

至于unpack和拆包粘包,就交给你来自己练手了,应该没有难度了吧!

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

------

转:: 刺鸟:用python来开发webgame服务端(4)的更多相关文章

  1. 转:: 刺鸟:用python来开发webgame服务端(3)

    来源:http://ciniao.me/article.php?id=11 --------------- 刺鸟原创文章,转载请注明出处    在之前的准备工作中,我们已经建立了一个socket服务器 ...

  2. 转:: 刺鸟:用python来开发webgame服务端(2)

    来源:http://ciniao.me/article.php?id=10 --------------- 刺鸟原创文章,转载请注明出处    就在刚才,我们用基于python下的Twisted库写了 ...

  3. 转:: 刺鸟:用python来开发webgame服务端(1)

    来源:http://ciniao.me/article.php?id=9 --------------- 刺鸟原创文章,转载请注明出处    在开始之前,先简单描述一下项目的特点:我要实现的是一个mm ...

  4. 转:: 刺鸟:用python来开发webgame服务端(5)

    来源:http://ciniao.me/article.php?id=19 --------------- 刺鸟原创文章,转载请注明出处    在前面的文章中,我们已经开始了不少逻辑功能的开发,在这期 ...

  5. Delphi XE5通过WebService开发Web服务端和手机客户端

    Delphi XE5通过WebService开发Web服务端和手机客户端介绍 我们开发一个三层的android程序 建立一个webservices  stand-alone vcl applicati ...

  6. 项目二:企业级java电商网站开发(服务端)

    声明:项目源于网络,支持正版教程,学习使用,仅记录在此 项目介绍 企业级java电商网站开发(服务端),模块划分:用户管理,商品管理,商品品类管理,订单管理,订单详情管理,购物车管理,收货地址管理,支 ...

  7. 开发zeroc ice应用入门(java开发ice应用,python开发ice应用,java与python结合开发ice服务)

    ice作为一种rpc框架,为主流平台设计,包括Windows和Linux,支持广泛的语言,包括C++,Java,C#(和其他.Net的语言,例如Visual Basic),Python,Ruby,PH ...

  8. cocos2d-x开发:服务端基础库封装

    元旦前面几天都在忙着面试,随后的几天也就一直在做服务端基础库开发方面的工作.对于服务端开发,是很久之前的事情了.那时候我还在大学读书,一直都是在倒腾服务端开发方面的东西,毕业后参加公司工作就是一直从事 ...

  9. iOS推送小结(证书的生成、客户端的开发、服务端的开发)

    1.推送过程简介 1.1.App启动过程中,使用UIApplication::registerForRemoteNotificationTypes函数与苹果的APNS服务器通信,发出注册远程推送的申请 ...

随机推荐

  1. WCF报错

    1."没有终结点在侦听可以接受消息的 http://localhost:8084/Service1.svc.这通常是由于不正确的地址或者 SOAP 操作导致的.如果存在此情况,请参见 Inn ...

  2. perl学习笔记——哈希

    哈希 哈希是一种数据结构,它和数组的相似之处在于可以容难任意多的值并能按需取用,而他和数组的不同在于索引的方式,数组是以数字为索引而哈希则是以名字为索引. 哈希的键是唯一的,哈希的值可以重复. 哈希的 ...

  3. hdu1698 Just a Hook (线段树区间更新 懒惰标记)

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  4. EazyUI主页框架搭建纯JS样例

    採用Jfinal+EazyUI  执行起来就好能够了 眼下还未增加后台代码  纯JS代码搭建的一个二级菜单+主页 客户换肤, 给使用EazyUI的新人一个高速可用的JS 搭建界面 也给自己保存下 界面 ...

  5. JS动态插入HTML后不能执行后续JQUERY操作

    通过js追加的html 发现 不能点击 执行函数   普通绑定事件:$('.btn1').click(function(){}绑定 事件委托   解决方法: $("body").d ...

  6. IOS 代理模式 DELEGATE

    代理模式:将我(类或结构体)需要来完成的工作交给另一个具备我所要求的能力的人(实现协议的对象)来执行 协议:具备哪些能力 例子:我要去买火车票,没时间买,委托黄牛买票 协议:买票 //: Playgr ...

  7. oracle获取时间毫秒数

    select (sysdate-to_date('1970-01-01','yyyy-mm-dd')-8/24)*24*60*60*1000-1* 60 * 60 * 1000  millisecon ...

  8. SqlServer+Topshelf+Quartznet做集群,定时任务分布式处理

    接触Quartznet之前,老东家用的是总监自己写的分布式任务框架,好用但是配置麻烦,unity,一个微软容器,配置节点错一个,整个使用到unity文件的项目全部跑不起来,这后果真的受不了... 目前 ...

  9. 檢查php文件中是否含有bom的php文件

    原文链接: http://www.cnblogs.com/Athrun/archive/2010/05/27/1745464.html 另一篇文章:<关于bom.php>,http://h ...

  10. Linux禁止非WHEEL用户使用SU命令

    通常情况下,一般用户通过运行"su -"命令.输入正确的rootpassword.能够登录为root用户来对系统进行管理员级别的配置. 可是.为了更进一步加强系统的安全性,有必要建 ...