Python C/S 網路程式設計(一)之 三種方法實現天氣預報小程式
阿新 • • 發佈:2018-12-03
1. 首先明白下協議棧和庫的概念:
- 協議棧(Protocol Stack): 是指網路中各層協議的總和,其形象的反映了一個網路中檔案傳輸的過程:由上層協議到底層協議,再由底層協議到上層協議。
- 庫(Library):主要用來解析要使用的網路通訊協議,包含Python內建標準庫和第三方庫。
網路程式設計實際上就是選擇並使用一個已經支援所需網路操作的庫的過程。
2. 下面就以一個例子來說明客戶端和伺服器端三種方式的通訊過程:
2.1 題目內容
獲取杭州市天氣預報,分別用第三方庫requests、基於http協議的標準庫http.client、基於傳輸層上socket三種方法實現。
2.2 開發過程
-
系統結構:
C/S架構,即實現服務端軟體與客戶端軟體基於網路通訊
- 通訊過程:
一次HTTP通訊:
瀏覽器從URL中解析出伺服器的主機名
瀏覽器將伺服器的主機名轉換成伺服器的IP地址
瀏覽器將埠號從URL中解析出來
瀏覽器建立一條與Web伺服器的TCP連線
瀏覽器向伺服器傳送一條HTTP請求報文
伺服器向瀏覽器回送一條HTTP響應報文
關閉連線,瀏覽器顯示文件
socket通訊過程:
1) S: 建立socket(根據地址型別、socket型別) 2) S:為socket繫結對應的IP地址和埠號 3) S:監聽埠號請求,接受使用者發來的連線請求(此時socket還沒開啟) 4) C:建立socket 5) C: 開啟socket,並通過IP地址+埠號試圖connect伺服器的socket 6) S: 接收到了使用者發來的socket連線請求,被動開啟socket,開始接收客戶端請求,直到使用者返回連線資訊。這時候伺服器的socket進入堵塞狀態,即accept();一直到客戶端返回連線資訊後才返回,然後開始接收下一個使用者端請求。 7) C:連線成功,開始向伺服器輸入狀態資訊 8) S:accept()返回,連線成功 9) C:寫入資訊 10) S:讀取資訊 11) C:關閉 12) S:關閉
-
網路協議:
(a) HTTP是個應用層協議
(b) socket是一個針對TCP/UDP程式設計的介面,socket是對TCP/IP協議的封裝,但是socket本身並不是協議,而好似一個呼叫介面(API),通過socket我們才能使用TCP/IP協議。
2.3 系統測試
2.4 原始碼分析
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests #用於獲取下載網站,即json網站頁面
import sys
import json #用於將頁面的json解析成Python能識別的字典表示
#輸入地點
weatherAdress = input("請輸入查詢地:")
if weatherAdress == 'E' or weatherAdress == 'e':
sys.exit(0); #關閉程式
#下載天氣JSON,
weatherJSon_url = 'http://wthrcdn.etouch.cn/weather_mini?city=%s'%(weatherAdress) #將連結定義為一個字串
response = requests.get(weatherJSon_url) #獲取並下載頁面,內容會儲存在respons.text成員變數裡
try:
response.raise_for_status() #若請求失敗則丟擲異常,正常無操作
except:
print('error')
#將json檔案格式匯入成python的格式
weatherData = json.loads(response.text)
#漂亮打印出天氣字典
#import pprint
#pprint.pprint(weatherData)
w = weatherData["data"]
print('現在是:%s 您在:%s'%(w['forecast'][0]['date'],w['city']))
print('溫度:%s %s'%(w['wendu'],w['ganmao']))
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
import http.client #用於提供支援HTTP協議的客戶端程式設計工具
import json
from urllib.parse import quote_plus #url編碼工具
base = '/api/weather/city/101210101'
def weaforecast(address):
path = '{}?address={}&sensor=false'.format(base, quote_plus(address))
#print(path)
#HTTPConnection例項(是一個類)表示與HTTP伺服器的連線
#例項化HTTPConnection,應傳遞一個主機和可選的埠號
connection = http.client.HTTPConnection('t.weather.sojson.com',80)
#使用指定的方法和url連結向伺服器傳送請求
connection.request('GET', path)
#呼叫伺服器返回的內容
rawreply = connection.getresponse().read()
#將json字串轉為Python物件
w = json.loads(rawreply.decode('utf-8'))
print('現在是:%s 您在:%s'%(w['time'],w['cityInfo']['city']))
#import pprint
#pprint.pprint(rawreply)
print('溼度:%s 溫度:%s 空氣質量%s,%s'%(w['data']['shidu'],w['data']['wendu'],w['data']['quality'],w['data']['ganmao']))
if __name__=='__main__':
address = '杭州'
weaforecast(address)
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
import socket
from urllib.parse import quote_plus
#一個HTTP請求報文由請求行、請求頭部、空行、請求資料4部分組成
#請求行由請求方法欄位(GET\POST...)、url欄位和HTTP協議版本3個欄位組成,以\n分離
request_text = """\
GET /api/weather/city/101210101?address={}&sensor=false HTTP/1.1\r\n\
Host: t.weather.sojson.com:80\r\n\ #
User-Agent: wea4\r\n\
Connection: close\r\n\
\r\n\
"""
def weaforecast(address):
sock = socket.socket() #建立socket例項
sock.connect(('t.weather.sojson.com', 80)) #客戶端建立連線
request = request_text.format(quote_plus(address)) #字串Python格式化
sock.sendall(request.encode('ascii')) #客戶端傳送訊息
raw_reply = b''
while True:
more = sock.recv(4096) #返回當前任意長度的可讀資料,期望長度4096
if not more:
break
raw_reply += more
print(raw_reply.decode('utf-8'))
if __name__=='__main__':
#address = input("請輸入地址:")
address = '杭州'
weaforecast(address)
2.5 理解
前面例子使用的協議棧包含4層:(第一層我沒做)
①. 谷歌地理編碼API: Pygeocoder——對如何用URL表示地理資訊查詢和獲取包含座標資訊的JSON資料進行封裝。
②. URL:Requests——標識了可以通過HTTP獲取的文件
③. HTTP層:使用原始TCP/IP套接字,http.client——支援面向文件的命令(GET)
④. TCP/IP套接字:socket——只處理位元組串的傳送和接收
3. 編碼與解碼
4. IP協議
-
下面的程式用來向執行程式的作業系統請求解析主機名 www.python.org 。即將主機名轉為IP地址。
-
特殊的IP地址段:
①. 127...:這一地址段由機器上執行的本地運用程式使用。其實是與同一機器上的一些其他服務或程式互動。127.0.0.1:這一地址被廣泛使用,表示“執行該程式的機器本身”,通常通過主機名localhost訪問。
②. 10...、172.16-31..、192.168..:這些IP地址段為私有子網內使用。沒有意義,並不對應可連線的任一主機,這樣可以把所有的網路流量隱藏。