1. python的模塊導入規則
參考
1.1 系統自帶模塊
系統自帶的模塊直接import導入
import time
import unittest
1.2 第三方下載模塊
第三方下載模塊也可以直接導入
import HTMLTestRunner
import requests
1.3 導入模塊的部分函數或類
from time import sleep,strftime
from time import *
1.4 導入自己寫的模塊
- 同文件夾: 直接import模塊名
- 跨文件夾: from [文件夾.文件夾.模塊] import [類(或函數)]
例如自定義了2個加法如下:
# class01/myAdd2.pydef myAdd2(a, b):print("自定義加法2")return a + b
# class02/myAdd2.pydef myAdd1(a, b):print("自定義加法1")return a + b
在文件夾class01下面創建一個addTest文件測試導入自己的加法模塊
from class01.myAdd2 import myAdd2
from class02.myAdd1 import myAdd1print(myAdd2(1,3))
print("*************")
print(myAdd1(2,4))
2. 網絡 - udp
參考
2.1 網絡通信概述
- 網絡就是一種輔助雙方或者多方能夠連接在一起的工具
- 使用網絡的目的:
- 聯通多方進行通信,把數據從一方傳遞給另外一方
- 為了讓不同電腦上運行的軟件之間能夠互相傳遞數據,就需要借助網絡的功能
- 總的來說:
- 使用網絡能夠把多方鏈接在一起,然后可以進行數據傳遞
- 所謂網絡編程就是,讓在不同的電腦上的軟件能夠進行數據傳遞,即進程之間的通信
2.2 ip地址(重點)
- 地址就是用來標記地點的
- ip地址: 用來在網絡種標記一臺電腦,比如: 192.168.1.1; 在本地局域網上是唯一的
- 每一個ip地址包括兩部分: 網絡地址和主機地址
2.2.1 A類ip地址
一個A類IP地址由1字節的網絡地址和3字節的主機地址組成,網絡地址的最高位必須是"0",
地址范圍: 1.0.0.1 ~ 126.255.255.254
二進制表示為: 00000001 00000000 00000000 00000001 ~ 011111110 11111111 11111111 11111110
可用的A類網絡有126個,每個網絡能容納 1677214個主機
2.2.2 B類ip地址
一個B類IP地址由兩個字節的網絡地址和2個字節的主機地址組成,網絡地址的最高位必須是"10"
地址范圍: 128.1.0.1 ~ 191.255.255.254
二進制表示位: 10000000 00000001 00000000 00000001 ~ 10111111 11111111 11111111 11111110
可用的B類網絡由16384各,每個網絡能容納65534主機
2.2.3 C類ip地址
一個C類IP地址由3字節的網絡地址和1字節的主機地址組成,網絡地址的最高位必須是"110"
地址范圍: 192.0.1.1 ~ 223.255.255.254
二進制表示位: 11000000 00000000 00000001 00000001 ~ 11011111 11111111 11111110 11111110
C類網絡可達2097152各,每個網絡能容納254個主機
2.2.4 D類地址用于多點廣播
d類ip地址第一個字節以"1110"開始,它是一個專門保留的地址
它并不指向特定的網絡,目前這一地址被用在多點廣播中
多點廣播地址用來依次尋址一組計算機, 地址范圍: 224.0.0.1 ~ 239.255.255.254
2.2.5 E類ip地址
以"1111"開頭,位將來使用保留
E類地址保留,僅作實驗和開發用
2.2.6 私有ip
這么多網絡ip中,國際規定有一部分ip地址是給我們的局域網使用,也就是屬于私網ip,不在公網中使用,它們的范圍是:
10.0.0.0 ~ 10.255.255.255172.16.0.0 ~ 172.31.255.255192.168.0.0 ~ 192.168.255.255
2.2.7 注意
ip地址 127.0.0.1 ~ 127.255.255.255 用于回路測試
如: 127.0.0.1 可以代表本機ip地址, 用 http://127.0.0.1
就可以測試本機種配置的web服務器
2.3 Linux命令(ping、ipconfig等)
- 本地網卡 :又叫本地回環,用來測試電腦是否能夠進行正常的網絡通信.
- 在linux中查看網卡信息:
ifconfig
- 假設網卡的名字位 ens40,關閉該網卡:
sudo ifconfig ens40 down
- 打開該網卡:
sudo ifconfig ens40 up
- 假設網卡的名字位 ens40,關閉該網卡:
2.4 端口(重點)
- ip是區分主機用的,端口是區分同一個主機種不同進程用的
- 端口就好比一個房子的門,是出入這件房子的必經之路
- 如果一個程序需要收發網絡數據,那么就需要這樣的端口
- 操作系統為了統一管理,對其進行了編號,這就是
端口號
2.4.1 端口號
端口是通過端口號來標記的,端口號只有整數,范圍是從0到65535
端口數不一樣的*nix系統不一樣,還可以手動修改
進程與程序: 一個程序在沒有運行起來的時候叫進程,在運行起來之后叫程序
2.4.2端口是怎樣分配的
端口號不是隨意使用的,而是按照一定的規定進行分配
端口的分類標準有好幾種,下面只介紹一下知名端口和動態端口
知名端口: 是眾所周知的端口號,范圍從 0 到 1023
80端口分配給HTTP服務
21端口分配給FTP服務
可以理解為,一些常用的功能使用的端口
動態端口: 范圍從 1024 到 65535
之所以是動態端口, 是因為它一般不固定分配某種服務,而是動態分配
動態分配: 當一個系統程序或應用程序需要網絡通信時,它向主機申請一個端口,主機從可用的端口號種分配一個供它使用,當這個程序關閉時,同時也就釋放了所占用的端口號
2.4.3 小結
一臺有ip的主機可以提供許多服務,比如HTTP、FTP、SMTP等,這些服務完全可以通過一個ip地址來實現。那么主機是怎么樣區分不同的網絡服務呢? 顯然不能只靠ip地址,因為ip地址與網絡服務的關系是一對多的關系。實際上是通過"ip + 端口號"來區分不同的服務的。
2.5 socket簡介
2.5.1 不同電腦上的進程之間如何通信
首要解決的問題是如何唯一標識一個進程,否則通信無從談起!
在1臺電腦上可以通過進程號(PID)來唯一標識一個進程,但是在網絡種這是行不通的.
其實TCP/IP協議族已經幫我們解決了這個問題,網絡層的"ip地址"可以唯一標識網絡種的主機,而傳輸層的"協議+端口"可以唯一標識主機種的應用進程(進程)
這樣利用"ip地址、協議、端口"就可以標識網絡中的進程了,網絡中的進程通信就可以利用這個標志與其它進程進行交互
注意:
- 所謂
進程
指的是: 運行的程序以及運行時用到的資源這個整體稱為進程- 所謂
進程通信
指的是: 運行的程序之間的數據共享
2.5.2 什么是socket
socket(簡稱: 套接字
)是進程通信的一種方式,它與其他進程通信的一個主要不同是: 它能實現不同主機的進程間通信,我們網絡上各種各樣的服務大多是基于Socket來完成通信的.下面是在python中使用socket的代碼
2.5.3 創建socket
在python中使用socket模塊的函數socket就可以完成:
import socket
socket.socket(AddressFamily, Type)
說明:
函數 socket.socket創建一個socket,該函數帶有兩個參數:
- Address Family: 可以選擇 AF_INET(用于internet進程間通信) 或者 AF_UNIX(同一臺機器進程間通信),實際工作中常用AF_INET
- Type: 套接字類型,可以是 SOCK_STREAM(流式套接字, 主要用于 TCP協議)或者 SOCK_DGRAM(數據報套接字,主要用于UDP協議)
創建一個tcp socket(tcp套接字)
import socket# 創建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# ...這里是使用套接字的功能 (省略) ...# 不用的時候,關閉套接字
s.close()
創建一個udp socket(udp套接字)
import socket# 創建udp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# ...這里是使用套接字的而功能 (省略) ...# 不用的時候,關閉套接字
s.close()
說明:
- 套接字使用流程與文件的使用流程很類似
- 創建套接字
- 使用套接字 收/發 數據
- 關閉套接字
2.6 udp網絡程序 - 發送、接受數據
2.6.1 使用socket發送upd數據
# 網絡編程/01-socket的基本使用
import socketdef main():# 1.創建一個udp套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 準備接收方的地址# "192.168.1.103" 表示目的ip地址# 8080表示目的端口dest_addr = ("192.168.0.106", 8080) # 地址是元組, ip是字符串,端口是數字# 3. 從鍵盤獲取數據send_data = input("請輸入要發送的數據: ")# 4. 發送數據到指定的電腦上的指定程序中udp_socket.sendto(send_data.encode("utf-8"), dest_addr)# 5. 關閉套接字udp_socket.close()print("----------run----------")if __name__ == "__main__":main()
.encode
: 將前面的數據編碼
【栗子】: 改寫上面的栗子,變為可以循環發送
# 網絡編程/03-socket的基本使用
import socketdef main():upd_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)while True:send_data = input("請輸入要發送的數據(exit退出): ")# 如果輸入的數據是 exit, 退出if send_data == "exit":breakelse:dest_addr = ("192.168.0.106", 8080)upd_socket.sendto(send_data.encode("utf-8"), dest_addr)upd_socket.close()if __name__ == "__main__":main()
2.6.2 使用socket接受udp數據
如果你的程序想收到數據,必須得有一個固定的端口,將會造成數據丟失.
下面提供了一個綁定端口的API
from socket import *def main():# 1. 創建套接字udp_socket = socket(AF_INET, SOCK_DGRAM)# 2. 綁定本地的相關信息,如果一個網絡程序不綁定,則系統隨機分配local_addr = ("192.168.0.106", 7788) # ip地址和端口號,ip一般不用寫,表示本既的任何一個ipudp_socket.bind(local_addr)# 3. 等待接收方發送的數據recv_data = udp_socket.recvfrom(1024) # 表示本次接收的最大字節數# 4. 顯示接收到的數據print(recv_data[0].decode('utf-8'))# 5. 關閉套接字udp_socket.close()if __name__ == "__main__":main()
2.7 upd綁定端口問題(重點)
2.7.1 在發送信息前綁定端口號
一般來說,在發送信息前,都會先綁定端口號,這樣方便收到接收端的信息
from socket import *def main():udp_socket = socket(AF_INET, SOCK_DGRAM)# 給udp綁定一個端口號udp_socket.bind(("", 7890))while True:send_data = input("請輸入要傳輸的數據: ")if send_data == "exit":breakelse:udp_socket.sendto(send_data.encode("utf-8"), ("192.168.0.106", 8080))udp_socket.close()if __name__ == "__main__":main()
在同一時刻,一個端口號只能綁定一個進程. 如果某一個端口被占用,其他的程序將無法使用該端口號
2.7.2 小結
1. 創建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
2. 綁定端口號
udp_bind(("", 7890))
3. 使用套接字收發數據
# 發送數據
udp_socket.sendto("xxx".encode("gbk"), ("192.168.0.1",8080))# 接收數據
udp_socket.recvfrom(1024) # 1024 代表一次接收的大小
4. 關閉套接字
udp_socket.close()
測試用的工具: mNetAssist
2.8 案例: udp聊天器
說明:
- 在電腦上編寫程序,需求如下:
- 獲取鍵盤數據,并發送給對方
- 接受數據并顯示
本地回環的使用:
如果你想在本地測試一下,數據在不同進程之間的通信,可以使用本地回環網卡, ip地址為 127.0.0.1. 它是固定不變的。注意本地回環,不能用于網絡通信~
from socket import *def send_msg(udp_socket):# 1.獲取鍵盤數據,并將其發送給對方msg = input("\n請輸入要發送的數據: ")# 2. 輸入對方的ip地址dest_ip = input("\n請輸入對方的ip地址: ")# 3. 輸入對方的portdest_port = int(input("\n請輸入對方的port: "))# 4. 發送數據udp_socket.sendto(msg.encode("gbk"), (dest_ip, dest_port))def recv_msg(udp_socket):# 1. 接收數據recv_msg = udp_socket.recvfrom(1024)print(recv_msg[0].decode("gbk"))def main():udp_socket = socket(AF_INET, SOCK_DGRAM)send_msg(udp_socket)recv_msg(udp_socket)udp_socket.close()if __name__ == "__main__":main()
-
以上程序在數據發送成功之后,會進入一種阻塞狀態(在此狀態下該端口號下的進程不會做任何事,等待喚醒)
-
套接字是一個可以同時收發數據的,下面說說 單工、半雙工、全雙工的概念:
- 單工: 考慮收音機,只能收而不能發送信息
- 半雙工: 考慮對講機, 同一時刻只能發送或者接收信息.不能同時進行
- 全雙工: 考慮打電話,可以同時進行收發信息(注意,套接字是全雙工的~)
操作系統會先將某個端口的數據存在內存中,當有程序調用將進程的數據時,會從操作系統中拿到該端口下的數據