小小千想和您聊一聊

当前位置: 首页> 技术分享> Python教程之Web编程之网络基础

Python教程之Web编程之网络基础

  本章学习目标

  l 掌握TCP/IP协议

  l 掌握HTTP协议

  l 了解Socket编程

  生活中,上班族每天需乘坐地铁或公交去公司工作,此过程中交通工具作为载体负责完成从家到公司的传输,如图3.1所示。与之对应,Web是以Internet(互联网)为载体负责完成数据的传输。

  图3.1 从家到公司图

  注意:本书所讲的Web编程是指基于Internet网络的应用编程。

  3.1 网络基础与TCP/IP协议

  3.1.1 网络基础概述

  网络学习的核心就是网络协议(计算机网络中进行数据交换而建立的规则、标准或者约定的集合)的学习,不同用户的终端数据可能采取不同的字符集,两者要进行通信,就必须统一标准,然后再进行通信,这些标准被称之为网络协议。正如普通话的出现解决了全国各地人们交流困难的问题。

  著名的OSI/RM模型(Open System Interconnection/Reference Model)将计算机网络体系结构的通信协议划分为七层,分别为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,具体如图3.2所示。

  图3.2 网络通信协议的层次图

  图3.2中七层结构主要分布在网络和主机上,其中每层都有不同的功能和协议,并且每层所使用设备也不尽相同,具体如图3.3所示。

  图3.3 各层次作用、协议及设备详图

  3.1.2 C/S与B/S架构介绍

  1.C/S架构

  C/S(Client/Server,客户端/服务器端)架构是一种比较早的软件架构,主要应用于局域网内,具体形式如图3.4所示。

  图3.4 两层C/S架构

  C/S架构分为客户机和服务器两层:第一层是在客户机系统上结合用户表示和业务逻辑,第二层是通过网络结合数据库服务器。简单的说就是第一层是用户表示层,第二层是数据库层。客户端和服务器直接相连,两部分的内容都非常重要,第一层的客户机不仅只有输入输出和运算能力,而且可以处理一些计算、数据存储等方面的业务逻辑事务;第二层的服务器主要承担事务逻辑的处理,相对来说事务很重,但是在客户机上可以完成部分逻辑事务,直接减轻服务器的负重,使网络流量增多。

  C/S架构的优点有:

  l 界面和操作可以很丰富

  l 安全性能易保证,可实现多层认证

  l 只有一层交互,因此响应速度较快

  2.B/S架构

  随着Internet和WWW的流行,以往C/S无法满足当前全球网络开放、互连、信息随处可见和信息共享的新要求,于是出现了B/S模式,即浏览器/服务器结构。它是C/S架构的一种改进,可以说属于三层C/S架构,具体如图3.5所示。主要是利用不断成熟的WWW浏览器技术,使用浏览器就可实现原来需要复杂的专用软件才能实现的强大功能,并节约了开发成本,B/S模式是一种全新的软件系统构造技术。

  图3.5 三层C/S架构

  第一层是浏览器,即客户端,处理极少部分的事务逻辑,如输入输出。由于客户不需要安装客户端,直接使用浏览器就能上网浏览,所以它面向的是大范围的用户,所以界面设计得比较简单,通用。

  第二层是WEB服务器,实现信息传送。当用户想要访问数据库时,就会首先向WEB服务器发送请求,WEB服务器统一请求后向数据库服务器发送访问数据库的请求,这个请求是以SQL语句实现的。

  第三层是数据库服务器,存放着大量的数据,十分重要。当数据库服务器收到WEB服务器的请求后,会对SQL语句进行处理,并将返回的结果发送给WEB服务器,接下来,WEB服务器将收到的数据结果转换为HTML文本形式发送给浏览器,也就是用户打开浏览器所看到的界面。

  B/S架构是应WEB技术的飞速发展而从传统的C/S架构发展而来,并且一举成为当今主要的网络架构。

  B/S架构的优点有:

  l 有浏览器即可

  l B/S架构可以直接放在广域网上,通过权限分配达到多用户访问,交互性比较强

  l B/S架构升级方式:升级服务器即可

  注意:本书之后的开发都是基于B/S架构。

  B/S架构虽说是C/S发展而来,但是它们还是存在比较大的差异,具体如表3.1所示。

  表3.1 C/S与B/S的比较

  3.1.3 TCP/IP协议与UDP协议

  TCP与UDP协议都是属于传输层协议,用于保证网络层数据传输。

  1.TCP/IP协议

  TCP/IP协议是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP等协议组成,主要是TCP协议和IP协议。通俗而言:TCP控制传输,一有问题就要求重新传输,直到所有数据正确并安全的传送到目的地,IP其实就是Internet分配给每一台互联网设备的唯一地址。

  IP协议接收由更低层(网络接口层,例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层——TCP或UDP层;相反,IP协议也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是否按顺序发送或者有没有被破坏,IP数据包中含有发送它的主机地址(源地址)和接收它的主机地址(目的地址)。

  TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时通过四次挥手断开连接;由于TCP是面向连接的,因此只能用于端到端的通讯。TCP提供的是一种可靠的数据流服务,采用“带重传的肯定确认”技术来实现传输的可靠性。TCP还采用一种称为“滑动窗口”的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。具体如图3.6所示。

  图3.6 TCP协议的三次握手和四次挥手

  接下来对图3.6中的三次握手和四次挥手进行详细解析。

  三次握手:首先Client端发送连接请求报文(一次握手);Server端接受连接后回复ACK报文,并为这次连接分配资源(二次握手);Client端接收到ACK报文后也向Server端发送ACK报文,并分配资源(三次握手),这样TCP连接就建立了。

  四次挥手:Client端发起中断请求,即发送FIN报文(一次挥手);Server端接收到FIN报文后,当Server端还有数据没有传送完成,先发送ACK报文给Client端,并继续传送数据,Client端接收到ACK报文后进入FIN_WAIT状态,等待Server端的FIN报文(二次挥手);当Server端确定数据已发送完成,则向Client端发送FIN报文(三次挥手);Client端收到FIN报文后,发送ACK报文通知Server端开始关闭连接并进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传(四次挥手);Server端收到ACK后,断开连接。Client端等待2MSL后没有收到回复,则证明Server端已正常关闭,Client端也可以关闭连接了,这样TCP连接就关闭了。

  注意:seq:“sequance”序列号;ack:“acknowledge”确认号;SYN:“synchronize”请求同步标志;ACK:“acknowledge”确认标志;FIN:“Finally”结束标志。

  2.UDP协议

  UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,因此可以实现广播发送。UDP通讯时不需要接收方确认,属于不可靠传输,可能会出现丢包现象,实际应用中要求开发者编程验证。

  UDP与TCP位于同一层,但它不管数据包的顺序、错误或重发。因此,UDP不被应用于使用虚电路的面向连接的服务,UDP主要用于面向查询、应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。

  每个UDP报文分UDP报头和UDP数据区两部分。报头结构具体如下:

  l 源端口号(16位)

  l 目标端口号(16位)

  l 数据报长度(16位)

  l 校验值(16位)

  使用UDP协议包括:TFTP(简单文件传输协议)、SNMP(简单网络管理协议)、DNS(域名解析协议)、NFS、BOOTP。

  在生活中,大家经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息能及时反馈回来,那么网络就是通的。

  3.TCP与UDP协议的区别

  虽然TCP与UDP都是属于传输层协议,作用也相同,但是这两者还是有比较大的差异的,具体如表3.2所示。

  表3.2 TCP与UDP的区别

  3.2 HTTP协议

  3.2.1 初识HTTP

  HTTP(HyperText Transfer Protocol,超文本传输协议)是一个应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。HTTP协议的主要特点可概括如下:

  l 支持客户/服务器模式。

  l 简单快速:客户向服务器请求服务时,只需传送请求方法和路径;请求方法常用的有GET、HEAD、POST,每种方法规定了客户与服务器联系的类型不同;由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

  l 灵活:HTTP允许传输任意类型的数据对象,正在传输的类型由Content-Type加以标记。

  l 无连接:无连接的含义是限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接,采用这种方式可以节省传输时间。

  l 无状态:HTTP协议是无状态协议,无状态是指协议对于事务处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大;另一方面,在服务器不需要前面的信息时它的应答就更快。

  HTTP协议永远都是客户端发起请求,服务器回送响应,具体如图3.7所示。

  图3.7 HTTP协议

  3.2.2 URL

  HTTP URL (URL是一种特殊类型的URI,包含了用于查找某个资源足够的信息)的格式示例如下:

  http://host[":"port][abs_path]

  l http:表示要通过HTTP协议来定位网络资源。

  l host:表示合法的Internet主机域名或者IP地址。

  l port:指定一个端口号,为空则使用缺省端口80。

  l abs_path:指定请求资源的URI,如果URL中没有给出abs_path,那么当它作为请求URI时,必须以“/”的形式给出,通常这个工作浏览器自动完成。

  URL示例如下:

  1、输入:www.1000phone.com

  浏览器自动转换成:http://www.1000phone.com /

  2、http:127.0.0.1:8080/index.html

  3.2.3 HTTP请求与响应

  HTTP是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,绝大多数的Web开发,都是构建在HTTP协议之上的。

  1.HTTP请求

  http请求由三部分组成,分别是:请求行、消息报头、请求正文。其中请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式示例如下:

  Method Request-URI HTTP-Version CRLF

  l Method表示请求方法

  l Request-URI是一个统一资源标识符

  l HTTP-Version表示请求的HTTP协议版本

  l CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)

  其中常用的请求方法及解释如表3.3所示。

  表3.3 常用请求方法及解释 

      消息报头在下一节详细介绍,请求正文是客户向服务器请求的内容主体。

  2.HTTP响应

  在接收和解析请求消息后,服务器返回一个HTTP响应消息;HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文。其中状态行格式示例如下:

  HTTP-Version Status-Code Reason-Phrase CRLF

  l HTTP-Version表示服务器HTTP协议的版本

  l Status-Code表示服务器发回的响应状态代码

  l Reason-Phrase表示状态代码的文本描述。

  其中状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

  l 1xx:指示信息——表示请求已接收,继续处理。

  l 2xx:成功——表示请求已被成功接收、理解、接受。

  l 3xx:重定向——要完成请求必须进行更进一步的操作。

  l 4xx:客户端错误——请求有语法错误或请求无法实现。

  l 5xx:服务器端错误——服务器未能实现合法的请求。

  常见的状态代码、描述及其说明如表3.4所示。

  表3.4 常见的状态码、描述及说明

  消息报头同样在下一小节详细介绍,响应正文是服务器返回的资源内容。

  3.2.4 HTTP消息报头

  HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始行(请求消息:请求行;响应消息:状态行),消息报头(可选),空行(只有CRLF的行),消息正文(可选)组成。

  HTTP消息报头包括普通报头、请求报头、响应报头、实体报头,每一个报头域都是由“名字+ :+空格+值”组成,消息报头域的名字是不区分大小写的。接下来一一讲解这四种报头。

  1.普通报头

  在普通报头中,有少数报头域用于所有的请求和响应消息,但并不用于被传输的实体,只用于传输的消息。

  Cache-Control用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制)。

  请求时的缓存指令包括:no-cache(用于指示请求或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached;响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage。

  Date普通报头域表示消息产生的日期和时间。

  Connection普通报头域允许发送指定连接的选项。例如:指定连接是连续,或者指定“close”选项,通知服务器,在响应完成后,关闭连接。

  2.请求报头

  请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。常用的请求报头如表3.5所示。

  表3.5 常用的请求报头

  请求报头示例如下:

GET /form.html HTTP/1.1 (CRLF)
  Accept:image/gif,image/x-xbitmap,image/jpeg,
  application/x-shockwave-flash,application/vnd.ms-excel,
  application/vnd.ms-powerpoint,application/msword,*/* (CRLF)
  Accept-Language:zh-cn (CRLF)
  Accept-Encoding:gzip,deflate (CRLF)
  If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)
  If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
  User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
  Host:www.guet.edu.cn (CRLF)
  Connection:Keep-Alive (CRLF)
  (CRLF)

  3.响应报头

  响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和对Request-URI所标识的资源进行下一步访问的信息。

  常用的响应报头如表3.6所示。

  表3.6 常用的响应报头

  4.实体报头

  请求和响应消息都可以传送一个实体;一个实体由实体报头域和实体正文组成,但并不是说实体报头域和实体正文要在一起发送,可以只发送实体报头域。实体报头定义了关于实体正文和请求所标识的资源的元信息。

  常用的实体报头如表3.7所示。

  表3.7 常用的实体报头

 3.3 Socket编程

  对于Internet应用,有基于标准协议开发的Web应用,同样还有基于非标准协议开发出来的其他应用,不管是哪种应用的开发,都需要了解Socket编程的知识,本节主要是讲解Socket基础,以及Socket的使用。

  3.3.1 Socket基础简介

  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。Socket工作的地方如图3.8所示。

  图3.8 Socket工作的地方

  3.3.2 Socket的原理及实战运用

  生活中,当你需要给一个朋友打电话的时候,应该先拨号,然后朋友接通电话使你和他达到一种连接,最终实现聊天;等聊天结束,双方挂掉电话即结束本次连接通话,其实这也就是TCP/IP协议族的原理,而基于TCP协议的Socket通信原理如图3.9所示。

  图3.9 基于TCP的Socket通信原理图

  Socket编程当中常用的函数及其描述如表3.8所示。

  表3.8 常用的函数

  接下来演示通过Python代码来实现Socket编程方法,基于TCP的Socket编程如例3-1所示。

  例3-1

  TCP服务器端的代码如skserver.py文件所示。


  skserver.py:
  1 import socket #引入Socket模块
  2
  3 HOST = '127.0.0.1' # 服务器主机地址
  4 PORT = 8088 # 服务器监听端口
  5 BUFFER_SIZE = 2048 # 读取数据大小
  6
  7 # 创建一个套接字(AF_INET说明使用IPv4地址,SOCK_STREAM指明是TCP)
  8 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  9 # 绑定主机和端口
  10 sk.bind((HOST, PORT))
  11 # 监听
  12 sk.listen(1)
  13
  14 print('Server start, listening {}'.format(PORT))
  15
  16 while True:
  17 # 建立连接,连接为建立的时候阻塞,并返回新的Socket对象
  18 conn, addr = sk.accept()
  19 while True:
  20 # 读取数据,数据还没到来阻塞
  21 data = conn.recv(BUFFER_SIZE).decode()
  22 if len(data):
  23 print('Server Recv Data: {}'.format(data))
  24 #向客户端发送数据
  25 conn.send(data.encode())
  26 print('Server Send Data: {}'.format(data))
  27 else:
  28 print('Server Recv Over')
  29 break
  30 #关闭连接
  31 conn.close()
  32 sk.close()


  先启动服务器代码,启动运行之后服务器会一直监听8088端口,直到客户端从8088端口发送过来数据,运行结果如图3.10所示。

  图3.10 例3-1服务器代码运行结果

  与服务器相对应的客户端代码如skclient.py文件所示。


skclient.py:
  1 import socket
  2 HOST = '127.0.0.1'
  3 PORT = 8088
  4 BUFFER_SIZE = 2048
  5 # 创建客户端套接字
  6 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  7 # 连接到服务器
  8 sk.connect((HOST, PORT))
  9 message = "Hello 1000phone"
  10 # 发起数据给服务器
  11 sk.sendall(message.encode())
  12 amount_received = 0
  13 amount_expected = len(message.encode())
  14 while amount_received < amount_expected:
  15 # 接收服务器返回的数据
  16 data = sk.recv(BUFFER_SIZE).decode()
  17 amount_received += len(data)
  18 print('Client Received: {}'.format(data))
  19 print('Closing connection to the server')
  20 sk.close()


  运行客户端代码显示服务器端传输过来的“message”,结果如图3.11所示。

  图3.11 例3-1客户端运行结果

  在客户端运行之后,服务器端显示客户端发送过来的数据,并显示服务器发送到客户端的信息,结果如图3.12所示。

  图3.12 例3-1服务器端显示结果

  由于UDP相对于TCP需要更少的控制,不需要建立连接,因此基于UDP的Socket编程会相对简单,具体如例3-2所示。

  例3-2

  UDP服务器端代码如uskserver.py文件所示。

  uskserver.py


  1 import socket #引入Socket模块
  2 HOST = '127.0.0.1' # 服务器主机地址
  3 PORT = 8089 # 服务器监听端口
  4 BUFFER_SIZE = 2048 # 读取数据大小
  5 # 创建一个套接字(AF_INET说明使用IPv4地址,SOCK_DGRAM指明是UDP)
  6 sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  7 # 绑定主机和端口
  8 sk.bind((HOST, PORT))
  9 print('Server start, listening {}'.format(PORT))
  10 while True:
  11 data, addr = sk.recvfrom(BUFFER_SIZE)
  12 data = data.decode()
  13 sk.sendto(('%s' % data).encode(), addr)
  14 print('Server Recv Data:{}'.format(data))
  15 sk.close()


  启动服务器代码,运行之后一直监听8089端口,直到客户端发送信息给服务器端,结果如图3.13所示。

  图3.13 例3-2服务器运行结果

  与之对应的客户端代码如uclient.py文件所示。

  uclient.py


 1 import socket
  2 HOST = '127.0.0.1'
  3 PORT = 8089
  4 BUFFER_SIZE = 2048
  5 # 创建客户端套接字
  6 sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  7 message = "Hello 千锋!!"
  8 # 发起数据给服务器
  9 sk.sendto(message.encode(),(HOST,PORT))
  10 print('Client Received: {}'.format(message))
  11 print('Closing connection to the server')
  12 sk.close()


  运行客户端代码,并显示输送到服务器端的消息内容,运行结果如图3.14所示。

  图3.14 例3-2客户端运行结果

  运行客户端后服务器端接收到数据,并显示,结果如图3.15所示。

  图3.15 服务器显示结果

  3.4 本章小结

  本章主要是介绍Web开发中所需要的网络知识基础,分为网络基础与TCP/IP协议、HTTP协议、Socket编程这三个部分来进行讲解,详细介绍了网络中的TCP/IP协议和HTTP协议以及Socket编程,最后以两个Socket编程的实例来加强大家对Socket编程的理解。正如本章开篇所讲,网络学习的核心就是网络协议的学习,大家一定要将这一部分内容给了解透彻,这可以为之后Web编程或网络编程打下良好的基础。

上一篇:HTML5工具初识之网页编辑器

下一篇:第2章 编程基础

QQ技术交流群

千锋Python官方①群
790693323

加入群聊