Python网络编程 5.1 字符串、字节与其传输

来源:互联网 发布:淘宝直通车入门教程 编辑:程序博客网 时间:2024/06/02 02:09

1.网络通信中字节的一个特点是,套接字接口将字节暴露了出来,使得其无论是对程序员还是对应用程序都是可见的。我们通常无可避免地要考虑在传输过程中表示数据的方式。这会给我们带来一些问题,而python这种高级语言是可以让我们避免这类问题的。


2.如果想通过套接字传输一个符号串,那么就需要使用某种编码方法来为每个符号分配一个确切的字节值。最流行的一个编码方式是ASCII码,定义了从0到127的字符代码:

for i in range(32,128,32):   print(' '.join(chr(j) for j in range(i,i+32)))
运行以上代码可以查看ascii码中可以表示的符号。为什么 i 的range要从32开始,是因为代码0~31表示用于输出显示的控制命令,而不是字母、数字或标点符号这样的实际图像。

编码方式有很多种,Unicode是目前的一个适用性很强的编码方式。

  • 对字符进行编码(encoding)意味着将真正的Unicode字符串转化为字节字符串。Python程序会将这些字节发送给外部的真实世界。
  • 对字节数据进行解码(decoding)意味着将字节字符串转化为真正的Unicode字符。
编码方式主要分为两大类,单字节编码和多字节编码,前者即每个字符与字节的值唯一对应,后者中每个字符可能会用多个字节来表示。由于在一些多字节编码方式中,用于表示不同字符的字节数是不同的,因此操作起来要多加小心。如果数据流被分割为多个部分,那么我们就不知道某个字符是否由于位于分割边界而从中间被分开。此时对部分接受的信息进行解码是很危险的。


3.大字节序小字节序与struct方法

大字节序就是将高位字节存储在前面,即放在内存的低地址字节,反之就是小字节序。不同的机器的存储字节序可能是不同的。Python 的struct模块提供了用于将数据与流行的二进制格式进行相互转换所需的各种操作。在准备用于网络套接字传输的二进制数据时,要遵循以下原则:

  • 使用struct模块生成用于网络传输的二进制数据,接收方接收到数据后使用struct模块进行解码。
  • 如果要自己控制网络传输的数据格式的话,在选择网络字节顺序时使用 ! 前缀。
  • 如果其他人设计了协议并使用小字节序,那么我们必须使用小字节序(以<表示)。

4.封帧与引用

如果使用UDP进行通信,那么协议本身就会使用独立的、可识别的块进行数据传输。但是如果网络出现了问题,就必须自己重新排列并重新发送这些数据块。如果选用的TCP进行通信,那么就要应对封帧的问题,即,如何分割消息,使得接收方能够识别消息的开始于结束。由于传递给sendall()的数据可能在实际网络传输中被分割成多个数据包,接受消息的程序可能需要进行多个recv()调用才能够读取完整的消息。因此就要考虑一个问题:接收方什么时候停止调用recv()才是最安全的?人们提出了一些解决方法。

  • 一个简单的想法是,只关注数据的发送,而不关注响应。接收方永远不会认为“数据已经够了”,然后向发送方发送响应。在这种情况下可以使用这种模式:发送方循环发送数据,直到所有数据都被传递给sendall()为止,然后使用close()关闭套接字。接收方只需要不断调用recv(),直到recv()最后返回一个空字符串(当发送方关闭套接字的时候会生成文件结束符,就是这里的空字符串),整个发送和接收的过程都结束。
  • 另一个方向是封帧(framing)。在发送时,我们不仅是发送单个消息,而是会发送多个数据块,并且在每个数据块前面加上数据块长度作为其前缀,这就意味着每个新的信息快对发送者来说都是可见的,可以使用数据块的长度为其打上标签,然后将该数据块置入发送流中。抵达信息结尾时,发送方可以发送后一个与接收方事先约定好的信号(比如发送一个长度为0的空字段),告诉接收方,所有数据块已经发送完毕。代码段 framing 展示了该想法的一个实现。该实现中,发送数据的方向是单一的,只在客户端向服务器发送。这个实现中使用的数据结构值得分析,每个消息前面都加上了一个struct作为前缀。struct中包含了使用4B(4个字节)表示的长度。由于I表示32位的无符号整数,因此每个帧的最大长度为4GB。本实例中代码向服务器发送三个连续的数据块,然后发送一个长度为0的消息,表示发送结束。     编写recv和send相关代码时一定要十分谨慎,只有仔细地在一个循环中调用recv(),代码才是正确的。

原创粉丝点击