1. 程式人生 > >Python 網路通訊協議 tcp udp區別

Python 網路通訊協議 tcp udp區別

網路通訊的整個流程

  在這一節就給大家講解,有些同學對網路是既熟悉又陌生,熟悉是因為我們都知道,我們安裝一個路由器,拉一個網線,或者用無限路由器,連上網線或者連上wifi就能夠上網購物、看片片、吃雞了,但是這一系列的神操作到底是怎麼讓我們上網了呢?讓我們起底揭祕!由於網路的內容非常的多,本篇部落格主要是學socket網路程式設計,所以我把網路這方面的內容放到了我另外一篇部落格上,這個部落格很簡單,不是什麼深入研究類的部落格,沒有學過網路的或者說對網路不太熟悉的同學可以去看看,地址是網路通訊的整個流程,有網路基礎的同學,可以直接往下面學習,如果你自認上學時是個學渣,也可以過去大致溜一眼~~~將來你面向的是開發,所有網路這一塊對你來講就是大致知道就可以了,但是以後想在技術上有深造,那麼就需要你深入的研究一下網路了,內容非常多,學海無涯~~

別忘了埠+IP能夠確定一臺電腦上的某一個應用程式~~

  那麼我們通過下面的程式碼簡單看一下socket到底是個什麼樣子,大概怎麼使用:下面的程式就是一個應用程式,和qq啊、微信啊是一樣的,都叫做應用程式。

  

import socket
#建立一個socket物件
server = socket.socket()  #相當於建立了一部電話
ip_port = ('192.168.111.1',8001) #建立一個電話卡
server.bind(ip_port) #插上電話卡
server.listen(5) #監聽著電話,我能監聽5個,接到一個電話之後,後面還能有四個人給我打電話,但是後面這四個人都要排隊等著,等著我第一個電話掛掉,再來第6個的時候,第六個人的手機會報錯
print('11111') #等著別人給我打電話,打來電話的時候,我就拿到了和對方的這個連線通道conn和對方的電話號碼addr conn,addr = server.accept() #阻塞住,一直等到有人連線我,連線之後得到一個元祖,裡面是連線通道conn和對方的地址(ip+埠) print('22222') print(conn) print('>>>>>>>>>',addr) while True: from_client_data = conn.recv(1024) #服務端必須通過兩者之間的連線通道來收訊息 from_client_data = from_client_data.decode('
utf-8') print(from_client_data) if from_client_data == 'bye': break server_input = input('明威說>>>>:') conn.send(server_input.encode('utf-8')) if server_input == 'bye': break conn.close() #掛電話 server.close() #關手機 test_server.py
View Code

 

  listen(3),這個3的意思是我連線著一個,後面還可以有三個排隊的,也就是支援4個人的服務,但是後面三個要排隊。

 

import socket
#建立一個socket物件
server = socket.socket()  #相當於建立了一部電話
ip_port = ('192.168.111.1',8001) #建立一個電話卡
server.bind(ip_port) #插上電話卡
server.listen(5) #監聽著電話,我能監聽5個,接到一個電話之後,後面還能有四個人給我打電話,但是後面這四個人都要排隊等著,等著我第一個電話掛掉,再來第6個的時候,第六個人的手機會報錯
print('11111')
#等著別人給我打電話,打來電話的時候,我就拿到了和對方的這個連線通道conn和對方的電話號碼addr
conn,addr = server.accept()  #阻塞住,一直等到有人連線我,連線之後得到一個元祖,裡面是連線通道conn和對方的地址(ip+埠)
print('22222')
print(conn)
print('>>>>>>>>>',addr)
while True:
    from_client_data = conn.recv(1024) #服務端必須通過兩者之間的連線通道來收訊息
    from_client_data = from_client_data.decode('utf-8')
    print(from_client_data)
    if from_client_data == 'bye':
        break
    server_input = input('明威說>>>>:')
    conn.send(server_input.encode('utf-8'))
    if server_input == 'bye':
        break
conn.close() #掛電話
server.close() #關手機

test_server.py
View Code

 

  注意:先執行server,然後再執行client,然後你會發現client這個檔案再輸出臺的地方讓你輸入內容,你輸入一個內容然後回車,你會發現server那邊的控制檯就輸出了以client傳送的內容

osi七層模型

網際網路的核心就是由一堆協議組成,協議就是標準,標準就是大家都認可的,所有人都按照這個來,這樣大家都能夠互相瞭解,互相深入了~~~比如全世界人通訊的標準是英語

 

五層通訊流程:

 

基於TCP和UDP兩個協議下socket的通訊流程

1.TCP和UDP對比

TCP(Transmission Control Protocol)可靠的、面向連線的協議(eg:打電話)、傳輸效率低全雙工通訊(傳送快取&接收快取)、面向位元組流。使用TCP的應用:Web瀏覽器;檔案傳輸程式。

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

直接看圖對比其中差異

 

繼續往下看

TCP和UDP下socket差異對比圖:

 

上面的圖只是讓大家感受一下TCP和UDP協議下,socket工作流程的不同,兩者之間的差異是tcp需要連線,udp不需要,有些同學是不是有些迷糊,老師,這裡面的bind、listen啥的都是什麼東西啊,我感覺人生是迷茫的!calm down!下面我們就分開兩者,細細學習!

2.TCP協議下的socket

來吧!先上圖!

基於TCP的socket通訊流程圖片:

 

雖然上圖將通訊流程中的大致描述了一下socket各個方法的作用,但是還是要總結一下通訊流程(下面一段內容)

先從伺服器端說起。伺服器端先初始化Socket,然後與埠繫結(bind),對埠進行監聽(listen),呼叫accept阻塞,等待客戶端連線。在這時如果有個客戶端初始化一個Socket,然後連線伺服器(connect),如果連線成功,這時客戶端與伺服器端的連線就建立了。客戶端傳送資料請求,伺服器端接收請求並處理請求,然後把迴應資料傳送給客戶端,客戶端讀取資料,最後關閉連線,一次互動結束

上程式碼感受一下,需要建立兩個檔案,檔名稱隨便起,為了方便看,我的兩個檔名稱為tcp_server.py(服務端)和tcp_client.py(客戶端),將下面的server端的程式碼拷貝到tcp_server.py檔案中,將下面client端的程式碼拷貝到tcp_client.py的檔案中,然後先執行tcp_server.py檔案中的程式碼,再執行tcp_client.py檔案中的程式碼,然後在pycharm下面的輸出視窗看一下效果。

server端程式碼示例(如果比喻成打電話)

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8898))  #把地址繫結到套接字
sk.listen()          #監聽連結
conn,addr = sk.accept() #接受客戶端連結
ret = conn.recv(1024)  #接收客戶端資訊
print(ret)       #列印客戶端資訊
conn.send(b'hi')        #向客戶端傳送資訊
conn.close()       #關閉客戶端套接字
sk.close()        #關閉伺服器套接字(可選)

tcp_server.py
View Code

client端程式碼示例

import socket
sk = socket.socket()           # 建立客戶套接字
sk.connect(('127.0.0.1',8898))    # 嘗試連線伺服器
sk.send(b'hello!')
ret = sk.recv(1024)         # 對話(傳送/接收)
print(ret)
sk.close()            # 關閉客戶套接字

tcp_client.py
View Code

在看UDP協議下的socket之前,我們還需要加一些內容來講:看程式碼

    server端

import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
# sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 
sk.bind(('127.0.0.1',8090))
sk.listen()
conn,addr = sk.accept()  #在這阻塞,等待客戶端過來連線
while True:
    ret = conn.recv(1024)  #接收訊息  在這還是要阻塞,等待收訊息
    ret = ret.decode('utf-8')  #位元組型別轉換為字串中文
    print(ret)
    if ret == 'bye':        #如果接到的訊息為bye,退出
        break
    msg = input('服務端>>')  #服務端發訊息
    conn.send(msg.encode('utf-8'))
    if msg == 'bye':
        break

conn.close()
sk.close()

只能與第一個客戶端通訊server端程式碼
View Code

    client端

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8090)) #連線服務端

while True:
    msg = input('客戶端>>>')  #input阻塞,等待輸入內容
    sk.send(msg.encode('utf-8'))
    if msg == 'bye':
        break
    ret = sk.recv(1024)
    ret = ret.decode('utf-8')
    print(ret)
    if ret == 'bye':
        break
sk.close()

只能與第一個客戶端通訊client端程式碼
View Code

  你會發現,第一個連線的客戶端可以和服務端收發訊息,但是第二個連線的客戶端發訊息服務端是收不到的

  原因解釋:     tcp屬於長連線,長連線就是一直佔用著這個連結,這個連線的埠被佔用了,第二個客戶端過來連線的時候,他是可以連線的,但是處於一個佔線的狀態,就只能等著去跟服務端建立連線,除非一個客戶端斷開了(優雅的斷開可以,如果是強制斷開就會報錯,因為服務端的程式還在第一個迴圈裡面),然後就可以進行和服務端的通訊了。什麼是優雅的斷開呢?看程式碼。 server端程式碼:
import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
# sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #允許地址重用,這個東西都說能解決問題,我非常不建議大家這麼做,容易出問題
sk.bind(('127.0.0.1',8090))
sk.listen()
# 第二步演示,再加一層while迴圈
while True:    #下面的程式碼全部縮排進去,也就是迴圈建立連線,但是不管怎麼聊,只能和一個聊,也就是另外一個優雅的斷了之後才能和另外一個聊
                #它不能同時和好多人聊,還是長連線的原因,一直佔用著這個埠的連線,udp是可以的,然後我們學習udp
    conn,addr = sk.accept()  #在這阻塞,等待客戶端過來連線
    while True:
        ret = conn.recv(1024)  #接收訊息  在這還是要阻塞,等待收訊息
        ret = ret.decode('utf-8')  #位元組型別轉換為字串中文
        print(ret)
        if ret == 'bye':        #如果接到的訊息為bye,退出
            break
        msg = input('服務端>>')  #服務端發訊息
        conn.send(msg.encode('utf-8'))
        if msg == 'bye':
            break
    conn.close()

優雅的斷開一個client端之後另一個client端就可以通訊的程式碼
View Code

     client端程式碼

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8090)) #連線服務端

while True:
    msg = input('客戶端>>>')  #input阻塞,等待輸入內容
    sk.send(msg.encode('utf-8'))
    if msg == 'bye':
        break
    ret = sk.recv(1024)
    ret = ret.decode('utf-8')
    print(ret)
    if ret == 'bye':
        break
# sk.close()

client端程式碼
View Code

3.UDP協議下的socket

老樣子!先上圖!

基於UDP的socket通訊流程:

 

總結一下UDP下的socket通訊流程

  先從伺服器端說起。伺服器端先初始化Socket,然後與埠繫結(bind),recvform接收訊息,這個訊息有兩項,訊息內容和對方客戶端的地址,然後回覆訊息時也要帶著你收到的這個客戶端的地址,傳送回去,最後關閉連線,一次互動結束