资源描述
V1.0,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第五章,发送和接收数据,通信应用软件设计,目标,掌握本机字节顺序以及网络字节顺序的区别,掌握,C,语言对齐规则以及由此导致的问题,掌握消息成帧的两种方式:文本字符格式和数据结构体方式。,掌握案例:一个简单的投票系统,2,概述,任何交换信息的程序都必须就如何编码信息(表示为一个位序列)达成一致,即发送信息是以何种格式,接收者必须以同样的信息格式进行解析。这种关于通过通信信道交换的信息的形式和含义的协定称为协议(,protocol,)。,大多数应用程序协议是依据由字段(,field,)序列构成的具体消息定义的。每个字段都包含一份特定的编码为位序列的信息。应用程序协议准确指定了发送者如何排列这些序列,以及接收者如何解释或解析它们。,自定义协议和标准协议。,3,整数的大小(,1,),在某种意义上,所有类型的信息最终都将被编码为固定大小的整数。,C,语言定义的几种整型:,char short,int,long,C,语言没有指定这些整型的存储位数的准确大小,而是把它留给实现来完成。因此整型存储位数大小可能因平台而异。,计算整型存储位数的大小是:,sizeof,,以字节为单位,例如,:,sizeof(int,),。,4,整数的大小(,2,),通过,TCP,连接发送,32,位整数,在不同的平台上可能存在不同的解释,可以解释为,int,,也可以解释为,long,。,C99,语言标准规范以一组可选类型的形式提供了一种解决方案:,int8_t int16_t int32_t int64_t,。这样可以有效地解决整数存储位数不一致的问题。,5,c99,c99,是在,c89,的基础上发展起来的,增加了基本数据类型,关键字和一些系统函数等。其实在初学阶段,C89,(,ANSI C,)和,C99,的区别是不易察觉的,所以不必太在意这个。,C99,有一部分是对于大字符集的优化,还加入了一些数据库函数,是,C89,之后的标准,我们用的,C,是,C89,标准的,,C+,是,C89,编写的,目前的,C99,标准其实在以前的编译器中就或多或少的支持了,目前完全支持的有这些:,GCC,、,Borland C+,等。,6,7,字节排序(,1,),对于需要多个字节进行编码的整数,必须回答以哪种顺序发送字节的问题。,例如:,123456787654321L,的十六机制为,0 x0000704885F926B1,00,00,70,48,B1,85,F9,26,大端,小端,8,字节排序(,2,),网络字节顺序:使用大端字节顺序,本机字节顺序:可能是大端也可能是小端顺序存储。,本机字节顺序与网络字节顺序之间转换函数:,htons,htonl,ntohs,ntohl,9,符号性与符号扩展,负数在,C,语言中采用补码表示。,负数值赋给无符号的变量时将使负数的符号位变量值的一部分。,在计算表达式的值时,首先要将变量的值加宽到本机(,int,)大小。例如,char a,b,;,sizeof(a+b,),的值为,4,10,手工编码整数,程序,BruteForceCoding.c,中的,EncodeIntBigEndian,使用大端表示法把任何给定的基本整数值作为指定字节数的序列存放在内存中的指定位置。,DecodeIntBigEndian,方法用于处理将给定长度的字节序列解码为,64,位的整数,并将其解释为大端序列。,BruteForceCoding.c,11,在流中包装,TCP,套接字(,1,),编码多个字节的整数可以使用流的方式在,TCP,套接字上传输。,FILE,工具流:通过,fdopen,(),调用把一个或多个,FILE,流与套接字描述符相关联。,FILE*,fdopen(int,socketdes,const char*mode);,int,fclose(FILE,*stream);,int,fflush(FILE,*stream);,frwrite,(.),fread,(),12,在流中包装,TCP,套接字(,2,),13,结构覆盖:对齐与填充(,1,),构造包含二进制数据(即多字节整数)的消息的最常用的方法是把,C,结构覆盖在一块内存区域上,并直接分配给结构的字段。,例如地址信息结构如下:,struct,addressInfo,uint16_t,streetAddress,;/,街道编号,int16_t,aptNumber,;/,公寓编号,uint32_t,postalCode,;/,邮编,addrInfo,;,14,结构覆盖:对齐与填充(,2,),发送结构体信息,(,假设结构体已经赋值),addrInfo.streetAddress,=,htons,(,addrInfo.streetAddress,),addrInfo.aptNumber,=,htons,(,addrInfo,.,aptNumber,),addrInfo.postalCode,=,htonl,(,addrInfo,.,postalCode,),if(send(sock,&,addrinfo,sizeof(addrinfo),0)!=,sizeof(addrinfo,),.,15,结构覆盖:对齐与填充(,3,),使用结构体来接收数据,16,结构覆盖:对齐与填充(,4,),一个,15,字节的消息结构体,,sizeof(integerMessage,),为,16,字节,而不是,15,字节。这是因为,C,语言特定的对齐规则造成的。,17,C,语言的对齐规则,数据结构是最大限度地对齐,即任何一个结构类型的变量的地址都可以被其最大的本机整型字段除尽。,类型为多字节的整数类型要与它们的大小对齐,即,int32_t,类型的变量开始地址总是可以被,4,除尽,而一个,uint16_t,的开始地址则保证可以被,2,除尽。,18,隐式字节填充,如果在,oneByte,字段与,twoBytes,字段之间插入一个字节的填充,那么就满足了字节对齐规则。,由编译器添加为填充的字节内容是未定义的。发送者以,16,字节发送,而接收者以,15,字节接收,那么很可能出现不正确的结果。,19,显式字节填充,这个结构在内存中的布置方式与原来申明的,integerMessage,完全一样,只不过程序员现在可以控制和访问填充字节的内容。,20,字符串和文本,可打印(显示)的字符串是表示信息的最常用的方式。,C,语言的字符集为,ASCII,码。汉子等多于一个字节进行编码的字符如何表示?,C99,扩展标准定义了一种,wchar_t,(宽字符)类型,用于存储可能为每个符号使用多个字节的字符集中的字符。,函数,wcstombs,和,mbstowcs,用于支持字节顺序与,wchar_t,的数组之间进行相互转换。,21,位操作:编码布尔值,位图(,bitmap,)是编码布尔信息的非常简洁的方式。位图的思想是:整数类型的每一个位都可以编码一个布尔值(,0,或,1,)。,掩码(,mask,)是把一个或多个特定的位设置为,1,并且清除所有其他的位。,位运算符,&|,22,构造、成帧和解析消息,案例:一个简单的“投票”协议,客户发送一条请求(,request,)消息给服务器,该消息包含候选人,ID,请求类型,是否响应,投票数。,23,客户端程序,步骤,建立,TCP,连接,将结构体,VoteInfo,型数据编码为发送字节序列,成帧并发送数据,接收返回响应信息,解码返回信息并打印,24,服务器程序,步骤,建立侦听套接字,反复接受连接和处理信息,等待连接,在流中包装套接字,接收并处理消息,直至连接关闭,25,成帧,成帧指的是允许接收者定位消息(或其一部分)的边界的普遍问题。,两种常规技术可以让接收者明确地查找消息的末尾:,基于定界符,显式长度,26,基于定界符,通过唯一标记指示消息的末尾。,基于定界符的方法的一个特例是:发送者发送消息后关闭连接,接收者在读取消息的最后一个字节后,会接收到一个流结束标志。,基于定界符的方法通常用于编码为文本的消息。,基于定界符方法的缺点是:消息自身绝对不能包含定界符。或者采用转义符的方式,但这将导致发送者和接收者必须扫描消息的每个字符,效率较低。,27,显式长度,在长度可变的字段或消息前附加一个长度字段,指出包含多少个字节。长度字段一般具有固定的大小:这会限制可以成帧的消息的最大大小。,显式长度方法更简单,一般用于二进制消息编码。,28,基于文本的消息编码,将投票消息表示为文本,由于消息中只需要表示数字和两个指示器,因此可以使用基本的,C,语言字符集,ASCII,。,空字符作为消息的定界符,每个消息的开头是一个所谓的“魔术字符串”,它允许接收者快速将消息设别为投票协议的消息,并且与通过网络达到的随机垃圾消息区分开。,29,二进制消息编码(,1,),使用数据结构体作为消息的传输格式。,30,二进制消息编码(,2,),31,
展开阅读全文