網絡層的“ip地址”可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的應用進程(進程)。這樣利用ip地址+協議+端口就可以標識網絡的進程了。
- 所謂
進程
指的是:運行的程序以及運行時用到的資源這個整體稱之爲進程(進程可以看成程序執行的一個實例。進程是系統資源分配的獨立實體,每個進程都擁有獨立的地址空間) - 所謂
進程間通信
指的是:運行的程序之間的數據共享
1.什麼是socket
socket(簡稱 套接字
) 是進程間通信的一種方式,它與其他進程間通信的一個主要不同是:它能實現不同主機間的進程間通信,我們網絡上各種各樣的服務大多都是基於 Socket 來完成通信的
2.python中創建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 協議)(當然還有很多其他參數如SOCK_RAW 但都不常用)
0.關與socket套接字的使用其實很簡單,跟文件的操作基本一致,3步:
1.創建套接字
2.使用套接字收/發數據
3.關閉套接字
1.創建一個tcp socket(tcp套接字)
import socket
# 創建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
.....代碼區.............
# 不用的時候,關閉套接字
s.close()
2.創建一個udp socket(udp套接字)
import socket
# 創建udp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# ...這裏是使用套接字的功能(省略)...
# 不用的時候,關閉套接字
s.close()
3.使用socket實現網絡通信
3.1使用socket進行udp通信,發送數據給服務器
from socket import *
# 1. 創建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 準備接收方的地址
# '192.168.1.1'表示目的ip地址,這裏是我本機的局域ip地址
# 8080表示目的端口,可以自己定義,等下一致即可
dest_addr = ('192.168.1.1', 8080) # 注意 是元組,ip是字符串,端口是數字
# 3. 從鍵盤獲取數據
send_data = input("請輸入要發送的數據:")
# 4. 發送數據到指定的電腦上的指定程序中,使用的是sendto()方法
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)
# 5. 關閉套接字
udp_socket.close()
1.在windows中運行“網絡調試助手”(百度即可)。在裏面配置如下端口號和通信協議,打開進程執行通信
2.執行上面程序給192.168.1.1:8080使用udp協議的進程發送了通信內容:Hello,UDP
可以發現在程序中發送的udp通信數據,在網絡調試助手中接收到了數據哈,如果多試幾次執行程序,發送不同的數據給192.168.1.1:8080,發現雖然接受了到了數據,但是如下可以看出每次程序使用的端口都不一樣 ,具體原因後面分析?
2.使用socket進行通信,實現接受和發送數據給“服務器”
from socket import *
# 1. 創建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 準備接收方的地址
dest_addr = ('192.168.1.1', 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()
在程序端發送數據,然後等待接受“網絡調式助手”發回的信息
4.關於端口問題
1.客戶端端口號一般是隨機分配的。
- 每重新運行一次網絡程序,上圖圈中的數字,不一樣的原因在於,這個數字標識這個網絡程序,當重新運行時,如果沒有確定到底用哪個,系統默認會隨機分配
- 記住一點:這個網絡程序在運行的過程中,這個就唯一標識這個程序,所以如果其他電腦上的網絡程序如果想要向此程序發送數據,那麼就需要向這個數字(即端口)標識的程序發送即可
-
一般情況下,在一臺電腦上運行的網絡程序有很多,爲了不與其他的網絡程序佔用同一個端口號,往往在編程中,udp的端口號一般不綁定。但是如果需要做成一個服務器端的程序的話,是需要綁定的,因爲訪問服務器的固定進程必須是唯一的。
2.綁定端口號
from socket import *
# 1. 創建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 綁定本地的相關信息,如果一個網絡程序不綁定,則系統會隨機分配
local_addr = ('', 9527) # 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網絡程序,可以不綁定,此時操作系統會隨機進行分配一個端口,如果重新運行此程序端口可能會發生變化
- 一個udp網絡程序,也可以綁定信息(ip地址,端口號),如果綁定成功,那麼操作系統用這個端口號來進行區別收到的網絡數據是否是此進程的