1. 程式人生 > >python高階3.網路-udp

python高階3.網路-udp

【黑馬python進階部分01網路udp】

【01網路通訊概述】
1、什麼是網路

. 網路是一種輔助雙方或者多方能夠連線在一起的工具
.如果沒有網路 可想 單機 的世界是多麼的孤單

單機遊戲(不能和遠在他鄉的朋友一起玩,如小時候玩的小霸王插卡遊戲機)

2.使用網路目的

就是為了聯通多方然後進行通訊用的,即把資料從一方傳遞給另外一方。

前面的學習編寫的程式都是單機的,即不能和其他電腦上的程式進行通訊。為了讓在不同的電腦上執行的軟體,之間能夠相互傳遞資料,就需要藉助網路的功能。

小總結:

.使用網路能夠把多方連結在一起,然後可以進行資料傳遞
.所謂的網路程式設計就是,讓在不同的電腦上的軟體能夠進行資料傳遞,即程序之間的通訊。網路作用示意圖

【02 ip地址】
1 、什麼是地址?
地址就是用來標記地點的

2、 ip地址的作用
ip地址:用來在網路中標記一臺電腦,比如192.168.1.1;在本地區域網上是唯一的,不允許重複。

【03 linux的ping和ifconfig等命令】

檢視網絡卡或配置網絡卡資訊:ifconfig,會顯示所有網絡卡的資訊。

測試遠端主機連通性:ping,通常用ping來檢測網路是否正常。

ip地址的分類–ipv4和ipv6(v是version的簡寫,版本)

ipv4:特點是有4組數字xxx.xxx.xxx.xxx(每一組裡面的最大值是255,最小值是0,共256種)
256256

256*256個不同的ip地址

ipv6: 為什麼會出現ipv6,因為ipv4的那麼多組不同的ip地址已經使用完了。

目前使用的主流ip地址還是ipv4

ipv4 xxx.xxx.xxx.xxx
每一個ip地址包括兩部分:網路地址和主機地址

A類:前面三組稱為網路號,後面一組稱為主機號。區域網前面標記相同的網路號,後面標記不同 的主機號。相同網路號的同一個區域網內,只能有254個不同的主機號,最小和的最大的0和256不能使用。

B類:前面2組稱為網路號,後面2組稱為主機號…

【04埠】
傳送資訊過程中的ip號和埠號作用

dest ip (目標ip):192.168.1.2
src ip(源ip):192.1681.1
dest port(目標埠):7788
src port(源埠):4567
content(傳輸資料):你好

目標ip號是通過伺服器 找到 目標電腦主機,
目標埠號是幫助找到目標主機的目標軟體程式。content是想要傳輸的資料.

如果一個程式需要收發網路資料,那麼就需要有這樣的埠。在linux系統中,埠可以有65536(2的16次方)之多!作業系統為了統一管理,所以進行了編號,即埠號。(埠號的數值是從0到65535)

知名埠:範圍從0到1023的為知名埠
比如80埠分給HTTP服務
21埠分配給FTP服務

動態埠:範圍是從1024到65535
該部分埠號一般不固定分配某種服務,而是動態分配。動態分配是指當一個系統程式或引用程式需要網路通訊時,它向主機申請一個埠,主機從可用的埠號中分配一個供它使用。當此程式關閉時,同時也就釋放了所佔用的埠號。

檢視埠號:用"netstat - an "檢視埠狀態
lsof -i [tcp/udp]:2425

小總結:通過"ip地址+埠號"來區分不同的服務,埠並非一一對應的。比如你的電腦作為客戶機訪問一臺WWW伺服器時,WWW伺服器使用“80”埠與你的電腦通訊,但你的電腦則可能使用“3457”這樣的埠。

【05socket簡介】
socket翻譯過來就是插口

1.不同電腦上的程序之間如何通訊

首要解決的問題是如何唯一標識一個程序,否則通訊無從談起!

在1臺電腦上可以通過程序號(PID)來唯一標識一個程序,但是在網路中這是行不通的。

其實TCP/IP協議族已經幫我們解決了這個問題,網路層的“ip地址”可以唯一標識網路中的主機,而傳輸層的“協議+埠”可以唯一標識主機中的應用程序(程序)。

這樣利用ip地址,協議,埠就可以標識網路的程序了,網路中的程序通訊就可以利用這個標誌與其它程序進行互動。

注意:
所謂程序指的是:執行的程式以及執行時用到的資源這個整體稱之為程序(在講解多工程式設計時進行詳細講解)
所謂程序間通訊指的是:執行的程式之間的資料共享。
後面課程中會詳細說到,像網路層等知識,不要著急。

2.什麼是socket(完成網路通訊必備的東西)
socket是程序間通訊的一種方式,它與其他程序間通訊的一個主要不同是:

它能實現不同主機間的程序通訊,我們網路上各種各樣的服務大多都是基於Socket來完成通訊的。例如微信、qq聊天等。

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()

說明
.套接字使用流程 與 檔案的使用流程很類似
1.建立套接字
2.使用套接字收/發資料
3.關閉套接字

【06udp網路程式-傳送、接收資料】

  1. udp網路程式-傳送資料

建立一個基於udp的網路程式流程很簡單,具體步驟如下:

1.建立客戶端套接字
2.傳送/接收資料
3.關閉套接字

在這裡插入圖片描述
程式碼如下:
#coding=utf-8
from socket import *

#1.建立udp套接字
udp_socket =socket(AF_INET,SOCK_DGRAM)

#2.準備接受方的地址
#'192.168.1.103’表示目的ip地址
#8080表示目的埠
dest_addr = (‘192.168.1.103’, 8080) # 注意 是元組,ip是字串,埠是數字

#3.從鍵盤獲取資料
send_data = input(“請輸入要傳送的資料:”)

#4.傳送資料到指定的電腦上的指定程式中
udp_socket.sendto(send_data.encode(‘utf-8’), dest_addr)

#5.關閉套接字
udp_socket.close()

執行現象:
在Ubuntu中執行指令碼:
在windows中執行“網路除錯助手”:

在這裡插入圖片描述
2.udp網路程式-傳送、接收資料
#coding=utf-8

from socket import *

#1.建立udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

#2.準備接收方的地址
dest_addr = (‘192.168.236.129’, 8080)

#3.從鍵盤獲取資料
send_data = input(“請輸入要傳送的資料:”)

#4.傳送資料到指定的電腦上
udp_socket.sendto(send_data.encode(‘utf-8’), dest_addr)

#5.等待接收對方傳送的資料
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大位元組數

#6.顯示對方傳送的資料
#接收到的資料recv_data是一個元組
#第1個元素是對方傳送的資料
#第2個元素是對方的ip和埠
print(recv_data[0].decode(‘gbk’))
print(recv_data[1])

#7.關閉套接字
udp_socket.close()

python指令碼:在這裡插入圖片描述
網路除錯助手截圖:
在這裡插入圖片描述
【07python3編碼轉換】

資料傳輸過程中都要轉換成bytes進行傳遞(即編碼),然後目標收到資料後進行相關檢視,必須要先將bytes轉換成字串(即解碼)

str->bytes:encode編碼
bytes->str:decode解碼

字串通過編碼成為位元組碼,位元組碼通過解碼成為字串。

text = ‘我是文字’
text
‘我是文字’

print(text)
我是文字

bytesText = text.encode()
bytesText
b’\xe6\x88\x91\xe6\x98\xaf\xe6\x96\x87\xe6\x9c\xac’

print(bytesText)
b’\xe6\x88\x91\xe6\x98\xaf\xe6\x96\x87\xe6\x9c\xac’

type(text)
<class ‘str’>

type(bytesText)
<class ‘bytes’>

textDecode = bytesText.decode()
textDecode
‘我是文字’

print(textDecode)
我是文字

其中decode()與encode()方法可以接受引數,其宣告分別為:

bytes.decode(encoding=“utf-8”, errors=“strict”)
str.encode(encoding=“utf-8”, errors=“strict”)

其中的encoding是指在解碼編碼過程中使用的編碼(此處指“編碼方案”是名詞),errors是指錯誤的處理方案。

【08udp繫結埠問題】

採用bind繫結埠號

1.udp網路程式-埠問題

會變的埠號
重新執行多次指令碼,然後在“網路除錯助手”中,看到的現象如下:
在這裡插入圖片描述
說明:
每重新執行一次網路程式,上圖中紅圈中的數字,不一樣的原因在於,這個數字標識這個網路程式,當重新執行時,如果沒有確定到底用哪個,系統預設會隨機分配

記住一點:這個網路程式在執行的過程中,這個就唯一標識這個程式,所以如果其他電腦上的網路程式如果想要向此程式傳送資料,那麼就需要向這個數字(即埠)標識的程式傳送即可

2.udp繫結資訊

《1》.繫結資訊

一般情況下,在一臺電腦上執行的網路程式有很多,為了不與其他的網路程式佔用同一個埠號,旺旺在程式設計中,udp的埠號一般不繫結

但是如果需要做成一個伺服器端的程式的話,是需要繫結的,想想看這又是為什麼呢?

如果報警電話每天都在變,想必世界就會亂了,所以一般服務性的程式,往往需要一個固定的埠號,這就是所謂的埠繫結

2.繫結示例

#coding=utf-8

from socket import *
#1.建立套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

#2.繫結本地的相關資訊,如果一個網路程式不繫結,則系統會隨機分配
local_addr = (’’, 7788) # ip地址和埠號,ip一般不用寫,表示本機的任何一個ip
udp_socket.bind(local_addr)

#3.等待接收對方傳送的資料
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大位元組數

#4.顯示接收到的資料
print(recv_data[0].decode(‘gbk’))

#5.關閉套接字
udp_socket.close()

執行結果:
在這裡插入圖片描述

總結:

一個udp網路程式,可以不繫結,此時作業系統會隨機進行分配一個埠,如果重新執行此程式埠可能會發生變化。

一個udp網路程式,也可以繫結資訊(ip地址,埠號),如果繫結成功,那麼作業系統用這個埠號來進行區別收到的網路資料是否是此程序的。

【09網路通訊過程】
在這裡插入圖片描述
說明:
網路通訊過程中,之所以需要ip、port等,就是為了能夠將一個複雜的通訊過程進行任務劃分,從而保證資料準確無誤的傳遞。

【10案例:udp聊天器】

說明:
在一個電腦中編寫1個程式,有2個功能
1.獲取鍵盤資料,並將其傳送給對方
2.接收資料並顯示
並且功能資料進行選擇以上的2個功能呼叫

要求
1實現上述程式

參考程式碼

import socket

def send_msg(udp_socket):
“”“獲取鍵盤資料,並將其傳送給對方”""
# 1. 從鍵盤輸入資料
msg = input("\n請輸入要傳送的資料:")
# 2. 輸入對方的ip地址
dest_ip = input("\n請輸入對方的ip地址:")
# 3. 輸入對方的port
dest_port = int(input("\n請輸入對方的port:"))
# 4. 傳送資料
udp_socket.sendto(msg.encode(“utf-8”), (dest_ip, dest_port))

def recv_msg(udp_socket):
“”“接收資料並顯示”""
# 1. 接收資料
recv_msg = udp_socket.recvfrom(1024)
# 2. 解碼
recv_ip = recv_msg[1]
recv_msg = recv_msg[0].decode(“utf-8”)
# 3. 顯示接收到的資料
print(">>>%s:%s" % (str(recv_ip), recv_msg))

def main():
# 1. 建立套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 繫結本地資訊
udp_socket.bind(("", 7890))
while True:
# 3. 選擇功能
print("="*30)
print(“1:傳送訊息”)
print(“2:接收訊息”)
print("="*30)
op_num = input(“請輸入要操作的功能序號:”)

    # 4. 根據選擇呼叫相應的函式
    if op_num == "1":
        send_msg(udp_socket)
    elif op_num == "2":
        recv_msg(udp_socket)
    else:
        print("輸入有誤,請重新輸入...")

if name == “main”:
main()

想一想

以上的程式如果選擇了接收資料功能,並且此時沒有資料,程式會堵塞在這,那麼怎樣才能讓這個程式收發資料一起進行呢?彆著急,學習完多工知識之後就解決了