《Python网络编程基础》第一章 读书笔记。

首先这本书还时非常好的,书中的示例代码都在更新,我上的代码都是他官方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\r\n\
Host: nominatim.openstreetmap.org\r\n\
User-Agent: Foundations of Python Network Programming example search4.py\r\n\
Connection: close\r\n\
\r\n\
"""

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'\xff\xfe4\x001\x003\x00 \x00i\x00s\x00 \x00i\x00n\x00.\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.\n'
    # 编码成字节码
    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设置。

 

很多概念性的东西,我学的还是比较累的。

posted @ 2020-11-05 22:45  就是想学习  阅读(156)  评论(0编辑  收藏  举报