IP地址
IP地址(Internet Protocol Address)是指互聯(lián)網(wǎng)協(xié)議地址,又譯為網(wǎng)際協(xié)議地址。 IP地址是IP協(xié)議提供的一種統(tǒng)一的地址格式,它為互聯(lián)網(wǎng)上的每一個(gè)網(wǎng)絡(luò)和每一臺主機(jī)分配一個(gè)邏輯地址,以此來屏蔽物理地址的差異。
換而言之,IP 地址就是標(biāo)識網(wǎng)絡(luò)中設(shè)備的一個(gè)地址,好比現(xiàn)實(shí)生活中某家公司的辦公地址。通過辦公地址,能找到某家公司。類似的,通過IP地址,能夠找到想找的某臺能夠進(jìn)行網(wǎng)絡(luò)通信的設(shè)備。
ip地址表現(xiàn)形式
IP 地址分為兩類: IPv4 和 IPv6
IPv4 是目前正在使用的ip地址。它由4段.
分隔的十進(jìn)制數(shù)字組成,每一段最大不超過255。(點(diǎn)分十進(jìn)制)
互聯(lián)網(wǎng)蓬勃發(fā)展,ip地址需求量迅速增大,為了避免ip地址用完,人們又設(shè)計(jì)出新的ip地址定義。IPv6出現(xiàn)。
IPv6由8段用:
分隔的十六進(jìn)制數(shù)字組成,每一段不超過四位。(冒號十六進(jìn)制)
IPv6一勞永逸地解決了ip地址不夠的問題,還改善了IPv4的不少問題。
不過,現(xiàn)在還不急于推廣IPv6。IPv4尚且夠用。所以說,IPv6是未來使用的ip地址。
查看ip地址
查看ip地址的方式有很多,這里介紹終端命令行方式。
Linux
ifconfig
- 全稱:network interfaces configuring
- ens33,lo表示網(wǎng)卡名
- ens33表示以太網(wǎng),其inet表示設(shè)備在網(wǎng)絡(luò)中的ip地址
- lo全稱“l(fā)oopback”,表示“回環(huán)”網(wǎng)絡(luò)接口。它不代表真正的網(wǎng)絡(luò)接口,而是一個(gè)虛擬的網(wǎng)絡(luò)接口, 其 IP 地址默認(rèn)是127.0.0.1,通常僅用于對本機(jī)的網(wǎng)絡(luò)測試。
- 域名(通常意義上的網(wǎng)址)是ip地址的別名,通過域名可以解析出對應(yīng)的ip地址。如域名
localhost
表示回環(huán)地址127.0.0.1。
Windows
ipconfig
檢查網(wǎng)絡(luò)是否正常
ping 域名/ip地址
- ping www.baidu.com 檢查是否能上公網(wǎng)(外部網(wǎng)絡(luò))
- ping 當(dāng)前局域網(wǎng)的ip地址 檢查是否在同一個(gè)局域網(wǎng)內(nèi)
- ping 127.0.0.1 檢查本地網(wǎng)卡是否正常
- 正常的話會(huì)顯示接收數(shù)據(jù)
- 不正常的話什么都沒有,光標(biāo)一直在等待
端口與端口號
端口(port),又稱為連接端口、協(xié)議端口(protocol port)。端口是數(shù)據(jù)傳輸?shù)耐ǖ馈?/p>
通過ip地址找到某臺網(wǎng)絡(luò)設(shè)備后,要想與某個(gè)特定的程序(進(jìn)程)進(jìn)行數(shù)據(jù)傳輸,就要找到該程序(進(jìn)程)對應(yīng)的端口,通過端口,進(jìn)行數(shù)據(jù)傳輸。
端口號是操作系統(tǒng)為了統(tǒng)一管理各程序的端口而編的號。端口號共有65536個(gè)。
ip地址相當(dāng)于公司的辦公地址,通過辦公地址找到公司后,要想和公司的某個(gè)部門通信,就要找到部門的”門“,這個(gè)“門”就是端口,門牌號就是端口號。
端口號分類
每個(gè)端口號唯一對應(yīng)一個(gè)端口。但端口可以供不同的程序使用。程序運(yùn)行時(shí)都要綁定一個(gè)端口,占用并使用一個(gè)端口號。
知名端口號
知名端口號是指眾所周知的端口號,范圍從0到1023。
這些端口號一般固定分配給一些系統(tǒng)服務(wù)進(jìn)程,比如21端口分配給FTP(文件傳輸協(xié)議)服務(wù),25端口分配給SMTP(簡單郵件傳輸協(xié)議)服務(wù),80端口分配給HTTP服務(wù)。
動(dòng)態(tài)端口號
一般程序員開發(fā)應(yīng)用程序可以使用的端口號稱為動(dòng)態(tài)端口號, 范圍是從1024到65535。
如果程序員開發(fā)的程序沒有特意設(shè)置端口號,操作系統(tǒng)會(huì)在動(dòng)態(tài)端口號的范圍內(nèi)隨機(jī)生成一個(gè)端口號給開發(fā)的應(yīng)用程序使用。
運(yùn)行一個(gè)程序默認(rèn)會(huì)有一個(gè)端口號,當(dāng)這個(gè)程序退出時(shí),所占用的這個(gè)端口號就會(huì)被釋放,可以供其他程序使用。如果沒有特殊的端口綁定操作的話,下次不一定就是這個(gè)。
TCP協(xié)議
前面我們已經(jīng)學(xué)習(xí)了
ip地址 → \rightarrow → 網(wǎng)絡(luò)設(shè)備 → \rightarrow → 端口號 → \rightarrow → 端口 → \rightarrow → 進(jìn)程
可通過ip地址和端口號凱定位某個(gè)特定進(jìn)程
進(jìn)程之間進(jìn)行數(shù)據(jù)傳輸,這是兩者之間的事情。
我們需要一個(gè)協(xié)議,來確保數(shù)據(jù)傳輸能夠按照某一規(guī)則成功進(jìn)行。
TCP協(xié)議就是其中之一。
概念
TCP協(xié)議 (Transmission Control Protocol),即傳輸控制協(xié)議,是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。
面向連接:TCP協(xié)議要求數(shù)據(jù)傳輸?shù)碾p方進(jìn)程只有在兩者的端口之間建立有效連接后,才能進(jìn)行數(shù)據(jù)傳輸。
可靠:字面意思。
基于字節(jié)流:可以傳輸大量二進(jìn)制數(shù)據(jù)。
TCP通訊步驟
-
建立連接
-
傳輸數(shù)據(jù)
-
斷開連接
特點(diǎn)
- 面向連接
- 通信雙方必須先建立好連接才能進(jìn)行數(shù)據(jù)的傳輸,數(shù)據(jù)傳輸完成后,雙方必須斷開此連接,以釋放系統(tǒng)資源。
- 可靠傳輸
- TCP 采用發(fā)送應(yīng)答機(jī)制(三次握手建立連接,四次握手?jǐn)嚅_連接)
- 超時(shí)重傳
- 錯(cuò)誤校驗(yàn)
- 流量控制和阻塞管理
socket套接字
實(shí)現(xiàn)數(shù)據(jù)傳輸,需要一個(gè)工具,它可以與端口綁定,負(fù)責(zé)數(shù)據(jù)傳輸?shù)囊磺惺聞?wù)。
它就是socket套接字(英文意思為插座)。
socket負(fù)責(zé)實(shí)現(xiàn)進(jìn)程之間的網(wǎng)絡(luò)數(shù)據(jù)傳輸,好比數(shù)據(jù)的搬運(yùn)工。
socket聚合了一系列與數(shù)據(jù)傳輸有關(guān)的函數(shù)
- connect()
- bind()
- listen()
- accept()
- send()
- recv()
- close()
TCP客戶端程序開發(fā)
步驟
- 創(chuàng)建客戶端程序的套接字對象
- 和服務(wù)端程序建立連接
- 發(fā)送數(shù)據(jù)
- 接收數(shù)據(jù)
- 關(guān)閉客戶端程序的套接字
1:創(chuàng)建客戶端程序的套接字對象
socket模塊
socket模塊是python內(nèi)置的處理socket的類
導(dǎo)入
import socket
socket類
socket對象創(chuàng)建
client_socket=socket.socket(AddressFamily, Type)
-
AddressFamily
代表ip地址類型
常量名 | 含義 |
---|---|
socket.AF_INET | IPv4類型 |
socket.AF_INET6 | IPv6類型 |
目前一般選擇socket.AF_INET
-
Type
代表socket
類型
常量名 | 含義 |
---|---|
socket.SOCK_STREAM | 面向連接 |
sokect.SOCK_DGRAM | 非面向連接 |
TCP協(xié)議下的程序選擇socket.SOCK_STREAM
- 返回socket套接字對象
- 這里用
client_socket
接收
所以最常見的這行代碼是:
client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
2:和服務(wù)端程序建立連接
connect方法
client_socket.connect(_address)
- _address是一個(gè)元組,格式為(host,port)。host是服務(wù)器ip地址(字符串),port是端口號。
- connect方法可以與ip地址為host,端口為port的服務(wù)端程序建立連接
如:
client_socket.connect(("192.168.147.1",8080))
3:發(fā)送數(shù)據(jù)
TCP協(xié)議要求只能發(fā)送二進(jìn)制數(shù)據(jù)。
字符串編碼
直接發(fā)送字符串是不行的,需要將字符串編碼為二進(jìn)制字節(jié)數(shù)據(jù)。
encode()
byte_str=string.encode(encoding)
- encoding代表編碼方式,為字符串,常用的有"gbk“(漢字國標(biāo)碼),”UTF-8“(萬國碼)…
- 返回string以encoding方式編碼后得到的字節(jié)流
send方法
client_socket.send(byte_str)
- 將
byte_str
傳輸?shù)揭呀?jīng)建立連接的服務(wù)端程序中
如:
send_data = "客戶端發(fā)來消息...".encode("gbk")
client_socket.send(send_data)
通過網(wǎng)絡(luò)調(diào)試助手看到的結(jié)果:
4:接收數(shù)據(jù)
recv方法
recv_data=client_socket.recv(_bufsize)
- 返回從已經(jīng)建立連接的服務(wù)端程序中接收到的字節(jié)流數(shù)據(jù)
- _bufsize為最大接受的字節(jié)大小
字符串解碼
decode()
string=byte_str.decode(encoding)
- 返回byte_str以encoding方式進(jìn)行解碼后得到的字符串
如:
用網(wǎng)絡(luò)調(diào)試助手充當(dāng)服務(wù)端
recv_date=client_socket.recv(1024)
recv_date=recv_date.decode("gbk")
print(recv_date)
5:關(guān)閉客戶端程序的套接字
close方法
client_socket.close()
- 關(guān)閉客戶端的socket,斷開連接
客戶端程序代碼匯總:
import socket # 導(dǎo)入socket庫
if __name__ == "__main__":
# 創(chuàng)建客戶端程序的socket對象
# socket.AF_INET:ip地址類型為IPv4
# socket.SOCK_STREAM:面向連接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 連接服務(wù)端程序
# 192.168.147.1為服務(wù)端ip地址
# 8080為服務(wù)端程序的端口號
client_socket.connect(("192.168.147.1", 8080))
# 將字符串?dāng)?shù)據(jù)編碼并發(fā)送至服務(wù)端程序
send_data = "客戶端發(fā)來消息...".encode("gbk")
client_socket.send(send_data)
# 接收來自服務(wù)端程序的字節(jié)流數(shù)據(jù)并解碼
recv_date = client_socket.recv(1024)
recv_date = recv_date.decode("gbk")
print(recv_date)
# 關(guān)閉客戶端程序的socket,斷開與服務(wù)端程序的連接
client_socket.close()
TCP服務(wù)端程序開發(fā)
步驟
- 創(chuàng)建服務(wù)端程序的套接字對象
- 綁定端口號
- 設(shè)置監(jiān)聽
- 等待接受客戶端的連接請求
- 接收數(shù)據(jù)
- 發(fā)送數(shù)據(jù)
- 關(guān)閉服務(wù)端程序的套接字
1:創(chuàng)建服務(wù)端程序的套接字對象
import socket
server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- 語法同客戶端程序
2:綁定端口號
服務(wù)端程序要讓客戶端程序能夠找到,所以一般要要綁定一個(gè)固定的端口號
bind方法
server_socket.bind(_address)
- _address為元組,格式為(host, port)。host是服務(wù)端本地ip地址,一般設(shè)為
“”
,自動(dòng)取。port為端口號,需指定以供客戶端程序來連接。
如:
server_socket.bind(("", 8989))
設(shè)置端口號復(fù)用
服務(wù)端程序運(yùn)行結(jié)束后,端口號并不會(huì)立即釋放,需等待2-3分鐘。我們可以在bind
方法前設(shè)置下面這行代碼來設(shè)置端口號復(fù)用,即程序運(yùn)行完立刻釋放端口號。
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
- 將
socket.SO_REUSEADDR
設(shè)置為True
,即勾選端口復(fù)用選項(xiàng)
3:設(shè)置監(jiān)聽
客戶端程序需要一直監(jiān)聽,直到接收到了客戶端程序發(fā)來的連接請求。
listen()方法
server_socket.listen(_backlog)
-
_backlog
為最大監(jiān)聽數(shù),即最多可以同時(shí)收到_backlog
個(gè)客戶端程序的連接請求,并進(jìn)行等待。server_socket在每個(gè)線程中只能同時(shí)連接一個(gè)客戶端程序,其他被監(jiān)聽的客戶端程序?qū)⒈蛔枞?,排?duì)等待連接。當(dāng)申請建立連接的客戶端程序超過最大監(jiān)聽數(shù)時(shí),若還有客戶端程序要發(fā)出連接請求,那么這個(gè)客戶端程序連排隊(duì)的機(jī)會(huì)都沒有,直接報(bào)錯(cuò)。
如:
server_socket.listen(1024)
- 代表最多可以同時(shí)監(jiān)聽1024個(gè)客戶端程序。
4:等待接受客戶端程序的連接請求
服務(wù)端程序要一直等待監(jiān)聽。如果有客戶端程序發(fā)來連接請求,服務(wù)端程序可以接受并處理。
accept()方法
new_server_socket,client_address=server_socket.accept()
- 沒有客戶端程序發(fā)來連接請求,則停在該行代碼不動(dòng)。
- 有客戶端發(fā)來連接請求,就接受請求,并建立連接。
- 返回一個(gè)新的socket對象,專門與進(jìn)行連接的客戶端程序進(jìn)行數(shù)據(jù)傳輸。這里用
new_server_socket
接收 - 以元組形式返回建立連接的客戶端程序的ip地址和端口號。這里用
client_address
接收。
5:接收數(shù)據(jù)
語法同客戶端程序,不過要用accept
返回的新套接字來處理。
6:發(fā)送數(shù)據(jù)
語法同客戶端程序,不過要用accept
返回的新套接字來處理。
7:關(guān)閉服務(wù)端程序的套接字
兩個(gè)套接字都要記得關(guān)閉。文章來源:http://www.zghlxwxcb.cn/news/detail-430477.html
new_server_socket.close()
server_socket.close()
- 關(guān)閉
new_server_socket
意味著對應(yīng)的這個(gè)客戶端程序和服務(wù)端程序斷開連接。服務(wù)端程序還可以繼續(xù)與其他新的客戶端程序連接。 - 關(guān)閉
server_socket
意味著服務(wù)端程序的套接字關(guān)閉,不再能與新的客戶端程序連接,但之前的連接還保留。
服務(wù)端程序代碼匯總:
import socket
if __name__ == '__main__':
# 創(chuàng)建服務(wù)端程序的socket對象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 設(shè)置端口號復(fù)用,讓程序退出端口號立即釋放
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 給程序綁定端口號
server_socket.bind(("", 8989))
# 設(shè)置監(jiān)聽
# 128:最大等待建立連接的個(gè)數(shù)
server_socket.listen(128)
# 等待客戶端建立連接的請求, 只有客戶端和服務(wù)端建立連接成功代碼才會(huì)解阻塞,代碼才能繼續(xù)往下執(zhí)行
# 1. 專門用于和客戶端程序通信的套接字: new_server_socket
# 2. 客戶端的ip地址和端口號: client_address
new_server_socket, client_address = server_socket.accept()
print("客戶端程序的ip地址和端口號:", client_address)
# 接收客戶端程序發(fā)送的字節(jié)流數(shù)據(jù)并解碼為字符串
recv_data = new_server_socket.recv(1024)
recv_data = recv_data.decode("gbk")
print(recv_data)
# 將字符串編碼得到的字節(jié)流傳輸給客戶端程序
send_data = "客戶端發(fā)來消息...".encode("gbk")
new_server_socket.send(send_data)
# 關(guān)閉服務(wù)端程序與客戶端程序傳輸專用的套接字
new_server_socket.close()
# 關(guān)閉服務(wù)端程序的套接字,結(jié)束向新的客戶端程序提供連接機(jī)會(huì)
server_socket.close()
多任務(wù)版服務(wù)端程序
通過多線程的方式處理多個(gè)客戶端程序的數(shù)據(jù)傳輸請求。文章來源地址http://www.zghlxwxcb.cn/news/detail-430477.html
import socket
import threading
def handle(handle_socket, address):
"""與客戶端程序進(jìn)行數(shù)據(jù)傳輸并處理"""
while True:
recv_data = handle_socket.recv(1024)
if recv_data: # 對收到的消息進(jìn)行處理
print(recv_data.decode("gbk"), address, sep=" from ")
handle_socket.send("OK,數(shù)據(jù)處理中...".encode("gbk"))
else: # 收到的消息為空
print("客戶端程序已退出...", address, sep=" from ")
break
# 終止和客戶端程序進(jìn)行通信
handle_socket.close()
if __name__ == '__main__':
# 創(chuàng)建服務(wù)端套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 設(shè)置端口號復(fù)用,讓程序退出端口號立即釋放
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 綁定端口號
server_socket.bind(("", 8080))
# 設(shè)置監(jiān)聽
server_socket.listen(128)
# 循環(huán)等待接收客戶端程序的連接請求
while True:
server_client_socket, client_address = server_socket.accept()
print("已成功連接客戶端程序...", client_address, sep=" from ")
# 每當(dāng)客戶端和服務(wù)端建立連接成功以后,創(chuàng)建一個(gè)子線程,不同子線程負(fù)責(zé)處理不同客戶端程序的消息
sub_thread = threading.Thread(target=handle, args=(server_client_socket, client_address))
# 設(shè)置守護(hù)主線程
sub_thread.Daemon = True
# 啟動(dòng)子線程
sub_thread.start()
# 服務(wù)端程序套接字可以不關(guān)閉,因?yàn)榉?wù)端程序需要一直運(yùn)行
到了這里,關(guān)于Python網(wǎng)絡(luò)編程基礎(chǔ)之ip地址,端口號,TCP,socket的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!