14.网络编程入门

计算机网络基础

TCP/IP模型

实现网络通信的基础是网络通信协议,这些协议通常是由互联网工程任务组(IETF)制定的。所谓“协议”就是通信计算机双方必须共同遵从的一组约定,例如怎样建立连接,怎样相互识别等,网络协议的三要素是:语法、语义和时序。构成我们今天使用的Inter的基础的是TCP/IP协议族,协议族就是一系列的协议及其构成的通信模型,也把这套东西称为TCP/IP模型。与国际标准化组织发布的OSI/RM这个七层模型不同,TCP/IP是一个四层模型,自顶向上依次是:网络接口层、网络层、传输层和应用层。如下图所示。

IP通常被翻译为网际协议,它服务于网络层,主要实现了寻址和路由的功能。接入网络的每一台主机都需要有自己的IP地址,IP地址就是主机在计算机网络上的身份标识。当然由于IPv4地址的匮乏,我们平常在家里、办公室以及其他可以接入网络的公共区域上网时获得的IP地址并不是全球唯一的IP地址,而是一个区域网中的内部IP地址,通过网络地址转换服务我们也可以实现对网络的访问。计算机网络上有大量的我们称为“路由器”的网络中继设备,它们会存储转发我们发送到网络上的数据分组,让从源头发出的数据最终能够找到传送目的的地通路,这项功能就是所谓的路由。

TCP全称传输控制协议,它是基于IP提供的寻址和路由器服务而建立起来的负责实现端到端可靠传输的协议,之所以将TCP称为可靠的传输协议是因为TCP想调用者承诺了三件事情:

  • 数据不传丢不传错(利用握手、校验和重传机制可以实现)。
  • 流量控制(通过滑动窗口匹配数据发送者和接收着之间的传输速度)。
  • 拥塞控制(通过RTT时间以及对滑动窗口的控制缓解网络拥堵)。

网络应用模式

  1. C/S模式和B/S模式。C指Client(客户端),通常是一个需要安装到某个宿主操作系统上的应用程序;B指Brower(浏览器),它几乎是所有图形化操作系统都默认安装了的一个应用软件;通过C或B都可以实现对S(服务器)的访问。
  2. 去中心化的网络应用模式。不管是B/S还是C/S都需要服务器的存在,服务器就是整个应用模式的中心,而去中心化的网络应用通常没有固定的服务器或者固定的客户端,所有应用的使用者既可以作为资源的提供者也可以作为资源的访问者。

基于HTTP协议的网络资源的访问

HTTP(超文本传输协议)

HTTP是超文本传输协议(Hyper-Text Transfer Proctol)的简称。维基百科解释为:超文本协议是一种用于分布式、协作式和超媒体信息系统的应用层协议,它是万维网数据通信的基础,设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,通过HTTP或者HTTPS(超文本传输安全协议)请求的资源由URI(统一资源标识符)来标识。阮一峰老师的《HTTP协议入门》

JSON格式

JSON(JavaScript Object Notation)是一种轻量级的数据交换语言,该语言以易于阅读的文字(纯文本)为基础,用来传输由属性值或者序列性的值组成的数据对象。尽管JSON是最初只是JavaScript中一种创建对象的字面量语法,但它在当下更是一种独立于语言的数据格式,很多编程语言都支持JSON格式数据的生成和解析,Python内置的json模块也提供了这方面功能。由于JSON是纯文本,它和XML一样都适用于异构系统之间的数据交换,而相较于XML,JSON显得更加的轻便和优雅。下面是表达同样信息的XML和JSON,而JSON的优势是相当直观的。

XML的例子:

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<message>
<from>Alice</from>
<to>Bob</to>
<content>Will you marry me?</content>
</message>

JSON的例子:

1
2
3
4
5
{
"from": "Alice",
"to": "Bob",
"content": "Will you marry me?"
}

requests库

requests是一个基于HTTP协议来使用网络的第三库,其官方网站有这样的一句介绍它的话:“Requests是唯一的一个非转基因的Python HTTP库,人类可以安全享用。”简单的说,使用requests库可以非常方便的使用HTTP,避免安全缺陷、冗余代码以及“重复发明轮子”(行业黑话,通常用在软件工程领域表示重新创造一个已有的或是早已被优化過的基本方法)。前面的文章中我们已经使用过这个库,下面我们还是通过requests来实现一个访问网络数据接口并从中获取美女图片下载链接然后下载美女图片到本地的例子程序,程序中使用了天行数据提供的网络API。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from time import time
from threading import Thread
import requests

# 继承Thread类创建自定义的线程类:
class DownloadHanlder(Thread):
def __init__(self,url):
super().__init__()
self.url = url
def run(self):
filename = self.url[self.url.rfind('/')+1:]
resp = requests.get(self.url)
with open('/Users/Hao' + filename,'wb') as f:
f.write(resp.content)
def main():
# 通过requests模块的get函数获取网络资源
# 下面的代码中使用了天行数据借口提供的网络API
# 要使用该数据借口需要在天行数据的网站上注册
# 然后用自己的Key替换掉下面代码中APIKey即可
resp = requests.get('http://api.tinanapi.com/meinv/?key=APIKey&num=10')
# 将服务器返回的JSON格式的数据解析为字典
data_model = resp.json()
for mm_dict in data_model['newslist']:
url = mm_dict('picUrl')
# 通过多线程的方式实现图片下载
DownloadHanlder(url).start()
if __name__ == '__main__':
main()

基于传输层协议的套接字编程

套接字是一套c语言写成的应用程序开发库,主要用于实现进程间通信和网路编程。实际开发使用套接字分为三类:流套接字(TCP套接字)、数据报套接字和原始套接字。

TCP套接字

TCP套接字就是使用TCP协议提供的传输服务来实现网络通信的编程接口。
下面代码实现一个提供日期的服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from socket import socket,SOCK_STREAM,AF_INET
from datetime import datetime

def main():
# 1.创建套接字对象并指定使用哪种传输服务
# family = AF_INET - IPv4地址
# family = AF_INET5 - IPv6地址
# type = SOCK_STREAM - TCP套接字
# type = SOCK_DGRAM - UDP套接字
# type = SOCK_RAW - 原始套接字
server = socket(family=AF_INET,type=SOCK_STREAM)
# 2.绑定IP地址和端口(端口用于区分不同的服务器)
# 同一时间在同一个端口上只能绑定一个服务否则报错
server.bind('192.168.1.2',6789)
# 3.开启监听 - 监听客户端连接到服务器
# 参数512可以理解为连接队列的大小
server.listen(512)
while True:
# 4.通过循环接收客户端的连接并作出相应的处理(提供服务)
# accept方法是一个阻塞方法如果没有客户端连接到服务器代码不会向下执行
# accept方法返回一个元组其中的第一个元素是客户端对象
# 第二个元素是连接到服务器的客户端的地址(由IP和端口两部分构成)
client,addr = server.accept()
print(str(addr) + '连接到了服务器.')
# 5.发送数据
client.send(str(datetime.now()).encode('utf-8'))
# 6.断开连接
client.close()
if __name__ == '__main__':
main()