首先这本书还时非常好的,书中的示例代码都在更新,我上的代码都是他官方github上面下载的最新代码。
第一章 客户端/服务器网络编程简介
获取经纬度,首先是通过三方包实现,很方便。
from geopy.geocoders import Nominatim if __name__ == '__main__': address = '207 N. Defiance St, Archbold, OH' user_agent = 'Foundations of Python Network Programming example search1.py' # user_agent = 'sidian' location = Nominatim(user_agent=user_agent).geocode(address) print(location.latitude, location.longitude)
输出
41.5427511 -84.3067015
1.2应用层
书中通过调用requests的三方包实现。
import requests def geocode(address): base = 'https://nominatim.openstreetmap.org/search' parameters = {'q': address, 'format': 'json'} user_agent = 'Foundations of Python Network Programming example search2.py' headers = {'User-Agent': user_agent} # 携带了参数与头部信息 response = requests.get(base, params=parameters, headers=headers) reply = response.json() print(reply[0]['lat'], reply[0]['lon']) if __name__ == '__main__': geocode('207 N. Defiance St, Archbold, OH')
输出与上面一样
1.3协议的使用。
书中主要介绍了http协议在应用层的使用很宽广。
示例代码
import http.client import json from urllib.parse import quote_plus base = '/search' def geocode(address): # 这里传入的headers与返回的response都是二进制文件。 path = '{}?q={}&format=json'.format(base, quote_plus(address)) user_agent = b'Foundations of Python Network Programming example search3.py' headers = {b'User-Agent': user_agent} # 这个定义了一个http协议的对象,参数只需要域名就可以了,因为协议已经写在方法里面了 connection = http.client.HTTPSConnection('nominatim.openstreetmap.org') connection.request('GET', path, None, headers) # 读取返回二进制数据 rawreply = connection.getresponse().read() reply = json.loads(rawreply.decode('utf-8')) print(reply[0]['lat'], reply[0]['lon']) if __name__ == '__main__': geocode('207 N. Defiance St, Archbold, OH')
可能是网络原因,没跑通。
1.4 一个原始的网络会话
书中已经用了一个简单的示例完成一个socket发送请求的情况。
#!/usr/bin/env python3 # Foundations of Python Network Programming, Third Edition # https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter01/search4.py # (The Google API originally used in this example now requires API keys, # so here's an alternative that calls openstreetmap.org.) import socket import ssl from urllib.parse import quote_plus #请求头所有信息 request_text = """ GET /search?q={}&format=json HTTP/1.1 Host: nominatim.openstreetmap.org User-Agent: Foundations of Python Network Programming example search4.py Connection: close """ def geocode(address): # 打开一个socket unencrypted_sock = socket.socket() # 连接socket,建立与服务器的三次握手 unencrypted_sock.connect(('nominatim.openstreetmap.org', 443)) # 建立ssl通道,进行通道加密 sock = ssl.wrap_socket(unencrypted_sock) ''' 也可以直接加密通道 sock = ssl.wrap_socket(unencrypted_sock) 加密通道与服务器进行连接,认证。 sock.connect(('nominatim.openstreetmap.org', 443)) ''' # 格式化请求头信息 request = request_text.format(quote_plus(address)) # 编码成字节码发送 sock.sendall(request.encode('ascii')) # 定义空字节码 raw_reply = b'' while True: # 接收返回的信息,设定块大小 more = sock.recv(4096) if not more: break raw_reply += more # 所有头信息,body都会返回 print(raw_reply.decode('utf-8')) if __name__ == '__main__': geocode('207 N. Defiance St, Archbold, OH')
输出
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 03 Dec 2020 08:27:37 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS,GET
1a7
[{"place_id":174011511,"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright","osm_type":"way","osm_id":379245933,"boundingbox":["41.5427373","41.5433134","-84.3067095","-84.3067012"],"lat":"41.5427511","lon":"-84.3067015","display_name":"North Defiance Street, Burlington, Archbold, Fulton County, Ohio, 43502, United States of America","class":"highway","type":"secondary","importance":0.61}]
0
上面显式了一个标准的response的输出情况。
1.5层层深入
略
1.6编码与解码
if __name__ == '__main__': # Translating from the outside world of bytes to Unicode characters. input_bytes = b'xffxfe4x001x003x00 x00ix00sx00 x00ix00nx00.x00' # 通过解码输出文字,这个作者真的用心良苦,用utf-16解码,让字节码与原丝字符串完全不一样 input_characters = input_bytes.decode('utf-16') # 通过repr输出更加厉害 print(repr(input_characters)) # Translating characters back into bytes before sending them. output_characters = 'We copy you down, Eagle. ' # 编码成字节码 output_bytes = output_characters.encode('utf-8') # 写入文件二进制格式,打开的时候就可以直接显示字符串,因为操作系统用软件打开文件,会自动帮你解码 with open('eagle.txt', 'wb') as f: f.write(output_bytes)
上面是示例代码,跟书中的完全不一样,写的真心的不错。
实例代码中通过直接向二进制文件写入字节码,后续也能通过打开,更好的解释了文件内保存的都是二进制,我们看到的只不过是已经解码以后的字符串信息。
1.7 网际协议
网际协议(IP)是为全世界通过互联网连接的计算机赋予统一地址系统的一种机制,它使得数据包能够从互联网的一端发送至另一端。
也就使所谓的IP协议,但一般我们很少去接触IP协议。我们接触最多到传输层。
1.8 IP地址
示例代码
import socket if __name__ == '__main__': hostname = 'baidu.com' # 获取域名的地址 addr = socket.gethostbyname(hostname) print('The IP address of {} is {}'.format(hostname, addr))
通过socket.gethostbyname的方法来获得域名对应的IP地址。
现在的IP4用的4个字节,后面切换IP6的话,就是16字节。
一些特殊的IP地址段
127.*.*.*:以127开头的IP地址是特殊的预留地址段,这一地址段由机器上运行的本地应用程序使用
127.0.0.1 == localhost 对应就是本机。
10.*.*.*
172.16-31.*.*
193.168.*.*
上面这三个IP地址段为私有网络(Private subnet)预留的。构建内网的时候,可以拿来使用。
1.9路由
路由一般也不用我们操心,自己操作系统或者路由器会根据路由表对数据进行发送。
是否是同一个子网可以通过ip与掩码来提现
192.168.1.9/24,就是前面24位相同就可以了,后面8位有256种可能,一个给网关,一个.0表示子网名,255记得应该是广播地址。
1.10数据包分组
学的也模模糊糊,就知道了以太网只支持1500B的数据包,一般UDP不设置DF(Don't Fragment)标记,tcp设置。
很多概念性的东西,我学的还是比较累的。