天天看點

python-socket程式設計(入門,網絡基礎)

一、網絡基礎

網絡建立的目的是為了資料互動(通信)

如何實作通信:

  1.建立好底層的實體連接配接媒體

  2.有一套統一的通信标準,稱之為網際網路協定

1.osi七層協定

網際網路協定按照功能的不同分為osi七層或tcp/ip五層或tcp/ip四層

python-socket程式設計(入門,網絡基礎)

每層運作的常見實體裝置

python-socket程式設計(入門,網絡基礎)

2.tcp/ip五層協定模型講解

2.1實體層:主要是基于電器特性發送高低電壓(電信号),高電壓對應數字1,低電壓對應數字0

2.2資料鍊路層:定義了電信号的分組方式,由于單純的0和1并沒有任何意義,必須規定電信号多少位一組,每組什麼意思

以太網協定:

  早期每個公司都有自己的分組方式,後來形成統一的标準,即以太網協定Ethernet

Ethernet規定

1.一組電信号構成一個資料包,叫做‘幀’,每一資料幀分成:報頭head和資料data兩部分

2.報頭(head):固定位元組數,裡面包含發送者,接收者,資料類型。資料(data):資料包的具體内容

mac位址

head中包含的源和目标位址的由來:以太網規定接入internet的裝置都必須具備網卡,發送位址和接收位址都是通過網卡來的

每塊網卡出廠時都被燒制上一個唯一的mac位址,前6位是廠商編号,後6位是流水線号

廣播:

有了mac位址,同一網絡内的兩台計算機就可以通信了   

2.3網絡層:不同網絡内想要通信,光靠Ethernet、mac位址和廣播并不可行,是以引入一套新的位址用來區分不同的網絡,這套位址就叫網絡位址

ip協定:

  規定網絡位址的協定叫ip協定,它定義的位址稱為ip位址,廣泛采用v4版本即ipv4,它規定網絡位址由32位2進制表示

  範圍為0.0.0.0 ---255.255.255.255

ip位址分為兩部分

  網絡部分:辨別子網

  主機部分:辨別主機

子網路遮罩:

  形式上等同于ip位址,也是32位二進制,網絡部分全部為1,主機部分全為0。

知道子網路遮罩我們就能判斷,任意兩個ip位址是否處在同一個子網絡。方法是将兩個ip位址分别進行AND運算(兩個都為1運算結果為1,否則為0),比較結果是否相同,如果相同的話就表明他們是在一個子網絡中,否則就不是         

總結ip協定的作用:1.為每台計算機配置設定ip位址,2确定這些位址是不是在同一個子網絡中。

ARP協定

  廣播的方式發送資料包,擷取目标主機的mac位址

2.4傳輸層:網絡層的ip幫我們區分子網,以太網層的mac幫我們找到主機,傳輸層建立端口到端口的通信,端口就是應用程式與網關關聯的編号   端口範圍0-65535,  0-1023位系統占用端口     

tcp協定:可靠傳輸,tcp資料包沒有長度限制,必須等到有回應才會繼續發送

udp協定:不可靠傳輸,不管有沒有收到響應隻管發送   

tcp的三次握手

python-socket程式設計(入門,網絡基礎)

注:TCP的TIME_WAIT需要等待2MSL,當TCP的一端發起主動關閉,三次揮手完成後發送第四次揮手的ACK包後就進入這個狀态,等待2MSL時間主要目的是:防止最後一個ACK包對方沒有收到,那麼對方在逾時後将重發第三次握手的FIN包,主動關閉端接到重發的FIN包後可以再發一個ACK應答包。在TIME_WAIT狀态時兩端的端口不能使用,要等到2MSL時間結束才可以繼續使用。當連接配接處于2MSL等待階段時任何遲到的封包段都将被丢棄。MSL即Maximum Segment Lifetime,就是最大封包生存時間,是任何封包在網絡上的存在的最長時間,超過這個時間封包将被丢棄。

常見面試題:為什麼建立連結是三次握手,不是二次,四次,關閉連結卻是四次不是其它

這是因為服務端在LISTEN狀态下,收到建立連接配接請求的SYN封包後,把ACK和SYN放在一個封包裡發送給用戶端。而關閉連接配接時,當收到對方的FIN封包時,僅僅表示對方不再發送資料了但是還能接收資料,己方也未必全部資料都發送給對方了,是以己方可以立即close,也可以發送一些資料給對方後,再發送FIN封包給對方來表示同意現在關閉連接配接,是以,己方ACK和FIN一般都會分開發送。

2.5應用層:規定應用程式的資料格式

二、socket介紹

socket是應用層與tcp/ip協定通信的中間軟體抽象層,它是一組接口,它吧複雜的TCP/IP協定隐藏在socket接口後面。           

基于檔案類型的套接字家族:

套接字家族的名字:AF_UNIX       

unix一切皆檔案,基于檔案的套接字調用的就是底層的檔案系統來取資料,兩個套接字程序運作在同一機器,可以通過通路同一個檔案系統間接完成通信

基于網絡類型的套接字家族:

套接字家族的名字:AF_INET

AF_INET被用于ipv4,AF_INET6被用于ipv6

三、套接字使用

python-socket程式設計(入門,網絡基礎)
import socket
socket.socket(socket_family,socket_type,protocal=0)
socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,預設值為 0。

擷取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

擷取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

由于 socket 子產品中有太多的屬性。我們在這裡破例使用了'from module import *'語句。使用 'from socket import *',我們就把 socket 子產品裡的所有屬性都帶到我們的命名空間裡了,這樣能 大幅減短我們的代碼。
例如tcpSock = socket(AF_INET, SOCK_STREAM)      

用戶端套接字函數

s.connect() 主動初始化TCP伺服器連接配接

s.connect_ex() connect()函數的擴充版本,出錯時傳回出錯碼,而不是抛出異常

公共用途的套接字函數

s.recv() 接收TCP資料

s.send() 發送TCP資料(send在待發送資料量大于己端緩存區剩餘空間時,資料丢失,不會發完)

s.sendall() 發送完整的TCP資料(本質就是循環調用send,sendall在待發送資料量大于己端緩存區剩餘空間時,資料不丢失,循環調用send直到發完)

s.recvfrom() 接收UDP資料

s.sendto() 發送UDP資料

s.getpeername() 連接配接到目前套接字的遠端的位址

s.getsockname() 目前套接字的位址

s.getsockopt() 傳回指定套接字的參數

s.setsockopt() 設定指定套接字的參數

s.close() 關閉套接字

面向鎖的套接字方法

s.setblocking() 設定套接字的阻塞與非阻塞模式

s.settimeout() 設定阻塞套接字操作的逾時時間

s.gettimeout() 得到阻塞套接字操作的逾時時間

面向檔案的套接字的函數

s.fileno() 套接字的檔案描述符

s.makefile() 建立一個與該套接字相關的檔案

基于tcp協定通信的套接字簡單                

python-socket程式設計(入門,網絡基礎)
python-socket程式設計(入門,網絡基礎)
from socket import socket, AF_INET, SOCK_STREAM
# socket 套接字
# AF_INET IPv4
# SOCK_STREAM socket流
IP = "127.0.0.1"
PORT = 8888
ADDRESS = (IP, PORT)
BUFSIZE = 1024

print("伺服器開啟了")
# 1.建立伺服器socket對象
serSocket = socket(AF_INET, SOCK_STREAM)
# 2.設定伺服器位址
serSocket.bind(ADDRESS)
# 3.設定連接配接管理隊列
serSocket.listen(5)
# 4.建立用戶端伺服器連接配接
cliSocket, addr = serSocket.accept()
print(cliSocket)
print(addr)
# 5.收發資料
data = cliSocket.recv(BUFSIZE)
print(data.decode("utf-8"))
cliSocket.send("伺服器傳回的資料".encode("utf-8"))
# 6.斷開用戶端
cliSocket.close()
# 7.關閉伺服器
serSocket.close()

print("伺服器關閉了")      

server

python-socket程式設計(入門,網絡基礎)
python-socket程式設計(入門,網絡基礎)
from socket import socket, AF_INET, SOCK_STREAM
IP = "127.0.0.1"
PORT = 8888
ADDRESS = (IP, PORT)
BUFSIZE = 1024
print("用戶端開啟了")
# 1.建立用戶端socket對象
cliSocket = socket(AF_INET, SOCK_STREAM)
# 2.連接配接伺服器位址
cliSocket.connect(ADDRESS)
print(cliSocket)
# 3.收發資料
cliSocket.send("用戶端發送的資料".encode("utf-8"))
data = cliSocket.recv(BUFSIZE)
print(data.decode("utf-8"))
# 4.關閉用戶端
cliSocket.close()
print("用戶端關閉了")      

client

焚膏油以繼晷,恒兀兀以窮年。