1. 程式人生 > >網絡編程—網絡基礎概覽、socket,TCP/UDP協議

網絡編程—網絡基礎概覽、socket,TCP/UDP協議

又是 輕量級 多次 所有 兩臺 瀏覽器 進行 網遊 max

網絡基礎概覽

socket概覽

socket模塊—TCP/UDP的實現

TCP/UDP總結

網絡基礎概覽


osi七層協議各層主要的協議

技術分享圖片
# 物理層傳輸電信號1010101010
# 數據鏈路層,以太網協議,arp協議。對這些信號進行分組,同時規範了分組形式--以太網協議,頭部是mac地址中間是信息,
# 網絡層:ip協議,arp協議幫忙找到mac地址,ip,子網掩碼,網關(下面有一些簡單概括)
# 傳輸層:tcp協議,udp協議
# (socket)就是一組接口,將復雜的tcp協議和udp協議隱藏在一組接口後面,用socket去組織數據,在用戶來看復雜的協議變為簡單的接口
# 會話層,表示層,應用層
#應用層加tcp/UDP報頭,加IP報頭,加mac地址報頭,然後用電信號發出去 #arp協議:A機器把請求通過交換機通過廣播的方式查找B計算機,判斷是不是自己的IP地址,不是的話丟棄,是的話返回計算機對應的mac地址給交換機, #交換機再通過單播的方式,返回給A機器 # ,如果不在同一個網段,再通過網關去找目標ip #socket分類: #基於文件類型的套接字家族: AF_UNIX #基於網絡類型的套接字家族: AF_INET 還有 AF_INET6被用於ipv6 #IP 端口 :在同一臺機器上,同一時間,只能有一個程序,占用同一個端口 #TCP:可靠的,面向連接的,(長連接),速度相對慢的
# UDP協議:不可靠,無連接,效率慢 #報文 數據包10101010就是報文 #我們在網絡上傳輸的所有數據,都叫數據包,數據包裏所有的數據都叫報文 #報文裏不止有數據 還有 ip地址,mac地址,端口號,所有的報文都有報頭,是各個協議規定的
osi七層概覽 技術分享圖片
    # tcp協議
        # 全雙工的通信協議:雙方都可以收發信息
            # 一旦連接建立起來,那麽連接兩端的機器能夠隨意互相通信
            # 面向連接的通信方式
            # 數據安全不容易丟失
            # 建立連接的 三次握手 ****** 建立了全雙工通信,我問你,你回答我順便問我,我回答你 三次握手
# 斷開連接的 四次揮手 ****** #全雙工通信,要一方發起關閉請求,另一方回應關閉,然後達成關閉一條但雙工 #然後另一方發起關閉請求,這一方回應關閉,達到關閉全雙工的目的,必須要進行 兩次的 發起回應
TCP的三次握手和四次揮手 技術分享圖片
# 物理層傳輸電信號1010101010
# 數據鏈路層,以太網協議,arp協議。對這些信號進行分組,同時規範了分組形式--以太網協議,頭部是mac地址中間是信息,
# 網絡層:ip協議,arp協議幫忙找到mac地址,ip,子網掩碼,網關(下面有一些簡單概括)
# 傳輸層:tcp協議,udp協議
# (socket)就是一組接口,將復雜的tcp協議和udp協議隱藏在一組接口後面,用socket去組織數據,在用戶來看復雜的協議變為簡單的接口
# 會話層,表示層,應用層
#應用層加tcp/UDP報頭,加IP報頭,加mac地址報頭,然後用電信號發出去

#arp協議:A機器把請求通過交換機通過廣播的方式查找B計算機,判斷是不是自己的IP地址,不是的話丟棄,是的話返回計算機對應的mac地址給交換機,
#交換機再通過單播的方式,返回給A機器
# ,如果不在同一個網段,再通過網關去找目標ip

#socket分類:
#基於文件類型的套接字家族: AF_UNIX
#基於網絡類型的套接字家族: AF_INET     還有  AF_INET6被用於ipv6


#IP 端口 :在同一臺機器上,同一時間,只能有一個程序,占用同一個端口
#TCP:可靠的,面向連接的,(長連接),速度相對慢的
# UDP協議:不可靠,無連接,效率慢
#報文 數據包10101010就是報文
#我們在網絡上傳輸的所有數據,都叫數據包,數據包裏所有的數據都叫報文
#報文裏不止有數據 還有 ip地址,mac地址,端口號,所有的報文都有報頭,是各個協議規定的




# qq 微信 飛秋 網遊 微博 歪歪  _基於應用的網絡程序
# 百度 微博 知乎 博客園 網易   _基於瀏覽器的網絡程序

# 網絡編程中的 - C/S架構
    # c client  客戶端
    # s server  服務端
# 網絡編程中的 - B/S架構
    # b broser  瀏覽器
    # s server  服務端
    # 不需要額外的安裝客戶端了,只需要一個網址就可以訪問
    # 輕量級  - 使用成本低
# B/S架構是C/S架構的一種特殊形式
# 手機上 : 瀏覽器 app

# 兩個py程序想要通信
    # 寫文件
# 在不同機器上的兩個py程序之間想要通信
    # 網絡

# 網絡的發展史
    # 網卡\網口
    # 兩臺機器之間 插上網線就可以通信
    # 網卡上 - mac地址
    # ip地址
        # 是4個點分十進制  - ipv4協議
            # 0.0.0.0 - 255.255.255.255
            # 127.0.0.1 本機
            # 內網字段 192.168.****
                    #  10.****
                    #  172.***
        # 6個點分十進制  - ipv6協議
            # 0.0.0.0.0.0  - 255.255.255.255.255.255
    # 交換機
        # 廣播
        # 單播
        # 組播
    # arp協議 : 通過IP地址獲取某一臺機器的mac地址
    # 子網掩碼
        # 子網掩碼 和 ip地址進行 按位 與 運算 就能得出一個機器所在的網段
        # 192.168.21.36
        # 11000000.10101000.00010101.00100100  #111111
        # 255.255.255.0   255.255.0.0
        # 11111111.11111111.11111111.00000000  #22222   1和2兩處按位與
        # 11000000.10101000.00010101.00000000  #局域網的網段
        # 192.168.21.0 網段
#IP協議作用兩個,一個是為每一臺計算機分配ip地址,二是確定哪些地址在同一個網段
    # 網關地址 : 整個局域網中的機器能溝通過網關ip與外界通信
    # 網段 : 子網掩碼 和 ip地址進行 按位 與 運算
    # 端口 : 0-65535
        # 8000-酷狗音樂  22-ssh  3306-mysql
        # python 網絡應用  8000
        # ip地址+端口號 : 在全網找到唯一的一臺機器+唯一的應用
        # 我們選擇端口 : 8000之後
    # tcp協議
        # 全雙工的通信協議:雙方都可以收發信息
            # 一旦連接建立起來,那麽連接兩端的機器能夠隨意互相通信
            # 面向連接的通信方式
            # 數據安全不容易丟失
            # 建立連接的 三次握手 ****** 建立了全雙工通信,我問你,你回答我順便問我,我回答你 三次握手
            # 斷開連接的 四次揮手 ****** #全雙工通信,要一方發起關閉請求,另一方回應關閉,然後達成關閉一條但雙工
                                         #然後另一方發起關閉請求,這一方回應關閉,達到關閉全雙工的目的,必須要進行 兩次的 發起回應
課上講義

socket概覽


Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。

技術分享圖片
其實站在你的角度上看,socket就是一個模塊。我們通過調用模塊中已經實現的方法建立兩個進程之間的連接和通信。
也有人將socket說成ip+port,因為ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程序。
所以我們只要確立了ip和port就能找到一個應用程序,並且使用socket模塊來與之通信。

3.套接字(socket)的發展史
套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 因此,有時人們也把套接字稱為“伯克利套接字”或“BSD 套接字”。一開始,套接字被設計用在同 一臺主機上多個應用程序之間的通訊。這也被稱進程間通訊,或 IPC。套接字有兩種(或者稱為有兩個種族),分別是基於文件型的和基於網絡型的。 

基於文件類型的套接字家族
套接字家族的名字:AF_UNIX

unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,可以通過訪問同一個文件系統間接完成通信

基於網絡類型的套接字家族
套接字家族的名字:AF_INET

(還有AF_INET6被用於ipv6,還有一些其他的地址家族,不過,他們要麽是只用於某個平臺,要麽就是已經被廢棄,或者是很少被使用,或者是根本沒有實現,所有地址家族中,AF_INET是使用最廣泛的一個,python支持很多種地址家族,但是由於我們只關心網絡編程,所以大部分時候我麽只使用AF_INET)
套接字理解和發展歷史

sockt在osi七層協議中的位置

TCP/UDP協議


TCP(Transmission Control Protocol)可靠的、面向連接的協議(eg:打電話)、傳輸效率低全雙工通信(發送緩存&接收緩存)、面向字節流。使用TCP的應用:Web瀏覽器;電子郵件、文件傳輸程序。

UDP(User Datagram Protocol)不可靠的、無連接的服務,傳輸效率高(發送前時延小),一對一、一對多、多對一、多對多、面向報文,盡最大努力服務,無擁塞控制。使用UDP的應用:域名系統 (DNS);視頻流;IP語音(VoIP)。

TCP和UDP的工作流程圖

socket模塊中TCP/UDP的實現:


基於TCP協議的socket:

技術分享圖片
import socket

sk = socket.socket()  #買電話,創建一個socket對象
# sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #買電話  網絡類型的socket類型和tcp
#默認值def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
#type=socket.SOCK_DARAM,UDP協議  datagram數據報文的縮寫

sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #避免服務重啟的時候出現 誤 OSError:address already in use
#sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind((127.0.0.1,8080))  #綁定電話卡,bind方法,接受一個元組 元組裏是 (ip,port)
sk.listen()          #監聽,看誰要給我打電話
#括號內可以放參數,比如 listen(5)只允許接收5個請求,就是說這裏 backlog-半鏈接池 大小是5,超過5個其他請求就進不來了
#防止黑客用大量的虛擬客戶端訪問服務端即洪水攻擊,來占滿backlog,讓其他客戶端進不來,其中一個辦法就是擴大backlog的空間

conn,addr = sk.accept()  #獲取connection 和 address   這裏conn 和addr 是兩個變量,不過通用都這麽寫
#這裏conn就是三次握手的連接

ret = conn.recv(1024)   #接收遠方來的電話的信息,並設定要接收多少大小,2048,4096,222,隨便你設,一般是1024
print(ret)
conn.send(bhi)  #接收到信息後,要回饋

ret = conn.recv(1024)
print(ret.decode(utf-8))
conn.send(收到.encode(utf-8))

conn.close()  #掛電話
sk.close()    #關手機

#有收必有發,收發必相等

# sever    -----    client
# send     -----    recv
# send     -----    recv
# recv     -----    send
#sever有一個send,client就要有一個receive,也可以連續send兩次或者多次,client同樣也要receive兩次或者多次
#兩邊的send和recv一定是對應的,不能只接不收,不能只收不接
#正因為tcp這個收發特性,保證了他是可靠連接



# import socket
# import time
# sk = socket.socket()  #創建一個socket對象
# #sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #默認值def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
#type=socket.SOCK_DARAM,UDP協議

# # sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# sk.bind((‘127.0.0.1‘,8898)) #給sever端綁定一個ip和端口
# sk.listen()            #listen括號內放數值 指backlog,默認指的是不限定訪問人數
# conn,addr = sk.accept()  #完成了三次握手,conn獲取到一個客戶端的鏈接
# #程序走在這會阻塞,等待客戶端連接
#
# while True:
#     ret = conn.recv(1024).decode(‘utf-8‘) #recv又是一個阻塞點,直到收到一個客戶端發來的消息
#     print(ret)
#     time_stamp = str(time.ctime(eval(ret)))
#     conn.send(bytes(time_stamp,encoding=‘utf-8‘))
#
# conn.close()  #關閉連接
# sk.close()   #如果不關閉還會繼續接收
server端-詳細解說版 技術分享圖片
import socket
sk = socket.socket()
sk.connect((127.0.0.1,8080))   #註意這裏不能用 bind,因為同一個端口,同一時間同一臺計算機只能綁定一個

sk.send(bhello)
# sk.send(‘你好‘.encode(‘utf-8‘))  #b‘hello‘
ret = sk.recv(1024)
print(ret)

sk.send(bytes(中午吃什麽,encoding=utf-8))
ret2 = sk.recv(1024)
print(ret2.decode(utf-8))

sk.close()

#有收必有發,收發必相等


#如果出現錯誤 OSError:address already in use
#就是因為系統還沒關閉通信,或者沒有寫關閉語句
client端

小練習:

1.基於tcp的聊天練習

技術分享圖片
import socket,time
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind((127.0.0.1,8898))
sk.listen()
conn,addr = sk.accept()

print(addr)
while True:
    ret = conn.recv(1024).decode(utf-8)
    print(ret)
    if ret == bye:
        conn.send(bbye)
        break
    info = input(>>> )+   +str(time.strftime(%Y-%m-%d %X))
    conn.send(bytes(info,encoding=utf-8))

conn.close()
sk.close()
server端-聊天兒 技術分享圖片
import socket,time
sk = socket.socket()
sk.connect((127.0.0.1,8898))

print(time.strftime(%Y-%m-%d %X))
while True:
    info = input(>>> )+   +str(time.strftime(%Y-%m-%d %X))
    sk.send(bytes(info,encoding=utf-8))
    ret = sk.recv(1024).decode(utf-8)
    print(ret)
    if ret == bye:
        sk.send(bbye)
        break
sk.close()
client端-聊天兒

2.基於TCP的記錄時間練習

技術分享圖片
import socket
import time
sk = socket.socket()  #創建一個socket對象
# sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind((127.0.0.1,8898)) #給sever端綁定一個ip和端口
sk.listen()            #listen括號內放數值 指backlog,默認指的是不限定訪問人數
conn,addr = sk.accept()  #完成了三次握手,conn獲取到一個客戶端的鏈接
#程序走在這會阻塞,等待客戶端連接

while True:
    ret = conn.recv(1024).decode(utf-8) #recv又是一個阻塞點,直到收到一個客戶端發來的消息
    print(ret)
    time_stamp = str(time.ctime(eval(ret)))
    conn.send(bytes(time_stamp,encoding=utf-8))

conn.close()  #關閉連接
sk.close()   #如果不關閉還會繼續接收
server端-記錄時間 技術分享圖片
import socket
import time
sk = socket.socket()
sk.connect((127.0.0.1,8898))

while True:
    ret = str(time.time())
    sk.send(bytes(ret,encoding=utf-8))
    time_struct = sk.recv(1024).decode(utf-8)
    print(time_struct)
    time.sleep(5)

sk.close()
client端-記錄時間

基於UDP的socket:


#UDP是必須要等客戶端主動發信息的,即被動的等待信息

#TCP主要客戶端連接,連接後服務器和客戶端都可以主動發信息

#客戶端發送消息的同時,還會自帶地址信息

#消息回復的時候,不僅需要發送消息,還需要把對方的地址填寫在內

技術分享圖片
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((127.0.0.1,8890))

msg,addr = sk.recvfrom(1024)
print(msg.decode(utf-8))
sk.sendto(bhi,addr)

sk.close()
server端-初識 技術分享圖片
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (127.0.0.1,8890)

sk.sendto(bhello,ip_port)
ret,addr = sk.recvfrom(1024)
print(ret.decode(utf-8))


sk.close()

#UDP不需要進行監聽,也不需要建立連接
#UDP是必須要等客戶端主動發信息的,即被動的等待信息
#TCP主要客戶端連接,連接後服務器和客戶端都可以主動發信息
#客戶端發送消息的同時,還會自帶地址信息
#消息回復的時候,不僅需要發送消息,還需要把對方的地址填寫在內
client端-初識

小練習:

1.udp實現的聊天兒

技術分享圖片
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
# sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind((127.0.0.1,8803))


while True:
    msg,addr = sk.recvfrom(1024)
    print(msg.decode(utf-8))
    info = (\033[34msever: \033+input(>>> )).encode(utf-8)
    sk.sendto(info,addr)
sk.close()
server端-聊天 技術分享圖片
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (127.0.0.1,8803)

while True:
    info = (\033[31mww: \033[0m + input(>>>> )).encode(utf-8)
    sk.sendto(info,ip_port)
    msg,addr = sk.recvfrom(1024)
    print(msg.decode(utf-8))
sk.close()
client端-聊天

2.udp更新時間

技術分享圖片
import socket
import time
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((127.0.0.1,8800))

msg,addr = sk.recvfrom(1024)
print(addr)
ret = msg.decode(utf-8)
print(ret)
ret2 = time.strftime(ret)
sk.sendto(ret2.encode(utf-8),addr)

sk.close()
server端-時間 技術分享圖片
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (127.0.0.1,8800)

time_format = %Y-%m-%d %X %a
sk.sendto(time_format.encode(utf-8),ip_port)
msg,addr = sk.recvfrom(1024)
print(addr)
print(msg.decode(utf-8))

sk.close()
client端-時間

TCP/UDP總結:

技術分享圖片
# TCP協議屬於 : 傳輸層
    # 面向連接 可靠的 字節流傳輸  長連接
# UDP協議屬於 : 傳輸層
    # 面向數據包的 無連接的 不可靠的 速度快 不占用連接

#UDP不會黏包,但是udp會丟包
#tcp會黏包,但是不會丟包
# 黏包成因:
# TCP(transport control protocol,傳輸控制協議)是面向連接的,面向流的,提供高可靠性服務。
# 收發兩端(客戶端和服務器端)都要有一一成對的socket,因此,發送端為了將多個發往接收端的包,更有效的發到對方,
# 使用了優化方法(Nagle算法),將多次間隔較小且數據量小的數據,合並成一個大的數據塊,然後進行封包。
# 這樣,接收端,就難於分辨出來了,必須提供科學的拆包機制。 即面向流的通信是無消息保護邊界的。
# 當發送端緩沖區的長度大於網卡的MTU時,tcp會將這次發送的數據拆成幾個數據包發送出去。
# MTU是Maximum Transmission Unit的縮寫。意思是網絡上傳送的最大數據包。MTU的單位是字節。
# 大部分網絡設備的MTU都是1500。如果本機的MTU比網關的MTU大,大的數據包就會被拆開來傳送,
# 這樣會產生很多數據包碎片,增加丟包率,降低網絡速度。
# 1.是因為tcp的拆包機制,使得消息沒有邊界
# 2.當發送端緩沖區的長度大於網卡的MTU時,產生了數據包碎片


#UDP不需要進行監聽,也不需要建立連接
#UDP是必須要等客戶端主動發信息的,即被動的等待信息
#TCP主要客戶端連接,連接後服務器和客戶端都可以主動發信息
#客戶端發送消息的同時,還會自帶地址信息
#消息回復的時候,不僅需要發送消息,還需要把對方的地址填寫在內

#有收必有發,收發必相等  (當收發不相等時候,TCP黏包,UDP丟包。如果len(發送)>len(接收)TCP會產生黏包, UDP會直接報錯,)
# sever    -----    client
# send     -----    recv
# send     -----    recv
# recv     -----    send
#sever有一個send,client就要有一個receive,也可以連續send兩次或者多次,client同樣也要receive兩次或者多次
#兩邊的send和recv一定是對應的,不能只接不收,不能只收不接
#正因為tcp這個收發特性,保證了他是可靠連接
#註意send不能發數字,要轉為str

# recv在自己這端的緩沖區為空時,阻塞
# recvfrom在自己這端的緩沖區為空時,就接收空
TCP/UDP總結

網絡編程—網絡基礎概覽、socket,TCP/UDP協議