Json在Ajax中已得到广泛的应用。相比XML,它有如下的优点:
1. 数据格式比较简单, 易于读写, 格式都是压缩的, 占用带宽小;
2. 易于解析这种语言, 客户端Javascript可以简单的通过eval()进行JSON数据的读取;
3. 支持多种语言, 包括Actionscript, C, C#, ColdFusion, Java, Javascript, Perl, PHP, Python, Ruby等语言服务器端语言, 便于服务器端的解析;
4. 在PHP世界, 已经有PHP-JSON和JSON-PHP出现了, 便于PHP序列化后的程序直接调用. PHP服务器端的对象、数组等能够直接生JSON格式, 便于客户端的访问提取。
除了BS模式,CS模式自然也可以使用JSON的格式。毕竟,我们可以简单的将其视为一个hashmap。那么,与一般的传送byte[]方式比较,JSON的优劣又体现在哪里?
带宽算劣势么?直接的JSON文本显然比byte[]占用更多空间,但JSON的格式在传送时候是压缩的,会不会有改善?
解析。JSON对多种语言提供了支持,便于解析。而python的pack和unpack风格,需要我们在各种语言中自行构建代码来支持。
String rule = "4'int'smallendian'time,1'int'smallendian'package_type,1'int'smallendian'msgType,6'string'bigendian'srcMAC," +"4'int'smallendian'nodeID,4'string'bigendian'nodeIP,4'string'bigendian'srcIP," +"4'int'smallendian'srcPort,1'int'smallendian'srcIDlen,-1'string'bigendian'srcID," + "6'string'bigendian'destMAC,4'string'bigendian'destIP,4'int'smallendian'destPort," + "1'byte'smallendian'languageFlag,2'int'smallendian'contentlen,-1'string'bigendian'msgcontent";
这是一个java对python的struct.unpack的模拟。当然,经过改良,我们可以相信其可以具有更好的可读性。类似如下的形式:
String rule = "4!i1!i1!i…"
至少在基本类型的处理上,我认为此形式可以很好的表达CS两端通信的接口。视此rule,则通信规则已了然于心。
需要注意的地方在与‘变长’和‘复杂类型’。
当传递一个变长字符串。可能需要如下的结构:
Len+Body
这样让我们的rule写起来就会费事。又如传递一个未知size的List,也是一个难处理的任务。
下面有一个简单的例子。Server端用python接收数据,以unpack方式接收数据,并以MysqlDB插入Mysql数据库;Client端用Erlang发送数据,以list_to_binary发送数据。
''' Created on 2009-3-18 @author: Administrator ''' from twisted.internet import protocol, reactor from time import ctime import struct import MySQLdb PORT = 9090 class TSServProtocol(protocol.Protocol): '''Data1 = [<<1:32/little, 1, 10>>, "srcmac", <<1234:32/little, 1, 2, 3, 4, 1, 2, 3, 4, 1234:32/little, 5>>, "abcde", "dstmac", <<1, 2, 3, 4, 1234:32/little, 1, 4:16/little>>, "love"],''' '''icc6si4s4sic5s6s4sich4s''' receiveData = ""; fieldname = ['time', 'protocoltype', 'msgtype', 'srcmac', 'nodeid', 'nodeip', 'srcip', 'srcport', 'srcid_len', 'srcid', 'dstmac', 'dstip', 'dstport', 'language_flag', 'msg_len1', 'msg_len2', 'msftext'] def connectionMade(self): clnt = self.clnt = self.transport.getPeer().host print '...connected from:', clnt def dataReceived(self, data): #self.transport.write('[%s] %s'% (ctime(),data)) #self.transport.write('[%s] %s' % (ctime(), 'x')) self.receiveData = self.receiveData + data #receiveData = receiveData + data #print self.receiveData length = 0 head = 0 head_len = 4 body = 0 while len(self.receiveData) >= head_len: head = self.receiveData[0:head_len] length = struct.unpack('i', head)[0] print 'length', length if len(self.receiveData) >= length & length != 0: print 'head', head self.onepckgdt = self.receiveData[0:length] self.receiveData = self.receiveData[length:] ### i1 = struct.unpack("c", self.onepckgdt[32])[0] print 'i1', ord(i1) tmp1 = self.onepckgdt[32 + 1 + ord(i1) + 15:32 + 1 + ord(i1) + 15 + 2] print 'length of tmp1', len(tmp1) tmp2 = struct.unpack("BB", tmp1) i2 = tmp2[0] + tmp2[1] * 256 print 'i2', i2 ### self.onepckgdt = self.onepckgdt[head_len:length] print "!iBB6si4s4siB" + str(ord(i1)) + "s" + "6s4siB" + "BB" + str(i2) + "s" body1 = struct.unpack("iBB6si4s4siB" + str(ord(i1)) + "s" + "6s4siB" + "BB" + str(i2) + "s", self.onepckgdt) insrt2MySQL(self.fieldname,body1) print self.receiveData print len(self.receiveData) ### else: break #print receiveData #for data in receiveData: # print ord(data) print '===' def insrt2MySQL(fieldname, fieldvalue): print "-" * 66 print 'len of fieldname', len(fieldname) print 'len of fieldvalue', len(fieldvalue) dict = {} for i in range(len(fieldvalue)): print fieldname[i], ":", type(fieldvalue[i]), fieldvalue[i] dict[fieldname[i]]=fieldvalue[i] print fieldname[i], ":", type(dict[fieldname[i]]), dict[fieldname[i]] print print "insert into msn(time, protocoltype)" print " values(",dict['time'],",",dict['protocoltype'],")" print "insert into msn(time, protocoltype)"+" values("+str(dict['time'])+","+str(dict['protocoltype'])+")" ### db=MySQLdb.connect(host="192.168.0.231",user="root",passwd="admin",db="test",charset="utf8") cursor=db.cursor() #sql statement #cursor.execute("insert into person(name, age, gender) values('wangzhi','25','male')") sql = "insert into msn(time, protocoltype) values(%s, %s)" cursor.execute(sql,(dict['time'], dict['protocoltype'])) cursor.execute("select * from msn") #get the result set result=cursor.fetchall() #iterate thtough the result set for i in result: print(i) print cursor.execute("select LAST_INSERT_ID()") result = cursor.fetchall() for i in result: print(i) print cursor.close pass factory = protocol.Factory() factory.protocol = TSServProtocol print 'waiting for connection...' reactor.listenTCP(PORT, factory) reactor.run()
%% Author: Administrator %% Created: 2009-3-10 %% Description: TODO: Add description to kvs -module(kvs6). %% %% Include files %% %% %% Exported Functions %% -export([start/0, st/2]). -export([start1/0]). -export([start_/0]). -export([m/2, q/2, y/2]). %% %% API Functions %% %% Return the Socket Handler. start() -> {ok, Socket} = gen_tcp:connect("192.168.0.93", 9090, [binary, {packet, 0}]), Socket. start1() -> {ok, Socket} = gen_tcp:connect("localhost", 9090, [binary, {packet, 0}]), Socket. start_() -> {ok, Socket} = gen_tcp:connect("localhost", 9090, [binary, {packet, 0}]), Data1 = [<<2:32, 1, 10>>, "srcmac", <<1234:32/little, 1, 2, 3, 4, 1, 2, 3, 4, 1234:32/little, 5>>, "abcde", "dstmac", <<1, 2, 3, 4, 1234:32/little, 1, 4:16/little>>, "hate"], sdpckg(Socket, Data1, 1). st(Socket, Data) -> _data = list_to_binary(Data), gen_tcp:send(Socket, _data). m(Socket, Repeate) -> Data1 = [<<Repeate:32/little, 1, 10>>, "srcmac", <<1234:32/little, 1, 2, 3, 4, 1, 2, 3, 4, 1234:32/little, 5>>, "abcde", "dstmac", <<1, 2, 3, 4, 1234:32/little, 1, 4:16/little>>, "love"], sdpckg(Socket, Data1, Repeate). q(Socket, Repeate) -> Data1 = [<<1:32/little, 2, 34, 1234:32/little, 1, 2, 3, 4>>, "srcmac", <<1, 2, 3, 4, 12345678:32/little>>], sdpckg(Socket, Data1, Repeate). y(Socket, Repeate) -> Data1 = [<<1:32/little, 3, 1234:32/little, 1, 2, 3, 4>>, "srcmac", <<1, 2, 3, 4, 1234:32/little>>, "dstmac", <<1, 2, 3, 4, 1234:32/little, 1, 5>>, "abcde", <<5>>, "fghij",<<4:16/little>>, "love"], sdpckg(Socket, Data1, Repeate). sdpckg(Socket, Data1, Repeate) -> _data = list_to_binary(Data1), Head = [<<(size(_data)+4):32/little>>], _head = list_to_binary(Head), L = lib_misc:for(1, Repeate, fun(I)->_data end), mylists:map(fun(X)->gen_tcp:send(Socket, _head), gen_tcp:send(Socket, X) end, L).
很明显Python本身的基础unpack在解决一些复杂问题时候力有不逮。struct模块允许创建一个等效于C结构的字符串,可以读写那些非Python程序生成的二进制文件。或者用于不同程序的网络通信。
在其他语言中,我们完全可以为变长类型和复杂类型定义新的标示,如“2X”,或者“nList”等等。
总而言之,JSON系列和byte[]系列的处理,进过一些考虑和工具类的构建,应该为各自找到较合适的应用场景。